You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django 5.0中无法用decorator_from_middleware将中间件转为装饰器求助

解决Django 5.0 + DRF中中间件转视图装饰器失败的问题

问题原因

你遇到的问题主要来自两个点:

  1. Django的decorator_from_middleware是为传统函数视图设计的,直接用于DRF APIView的类方法时,需要适配类方法的装饰器逻辑。
  2. 你的中间件仅实现了__call__方法,作为装饰器使用时,无法精准适配DRF的视图调用流程。

方案一:修正装饰器在DRF类视图中的使用方式

使用Django的method_decorator将中间件转来的装饰器适配为类方法可用的装饰器:

from django.utils.decorators import decorator_from_middleware, method_decorator
from users.middleware import SimpleMiddleware
from rest_framework.views import APIView
from rest_framework.response import Response
import status

simple_decorator = decorator_from_middleware(SimpleMiddleware)

class UserPoolInfo(APIView):
    # 用method_decorator包裹装饰器,适配类方法
    @method_decorator(simple_decorator)
    def get(self, request):
        user_manager_object = UserManager()
        user_pool_info = user_manager_object.get_user_pool_info()
        response_data = {
            "status":"Success",
            "statusCode": status.HTTP_200_OK,
            "message":"fetched user pool information",
            "data": user_pool_info
        }
        return Response(response_data, status.HTTP_200_OK)

如果需要给类中多个方法统一应用装饰器,可以这样写:

@method_decorator(simple_decorator, name='get')
@method_decorator(simple_decorator, name='post')
class UserPoolInfo(APIView):
    # 视图方法...

方案二:直接编写DRF专属的验证装饰器(更推荐)

因为你的需求是Token验证+角色检查,直接编写DRF风格的装饰器比转中间件更灵活,也更贴合DRF的请求处理流程:

步骤1:编写自定义装饰器

# users/decorators.py
from rest_framework import exceptions
from rest_framework.response import Response
import status

def token_and_role_required(allowed_roles=None):
    allowed_roles = allowed_roles or []
    def decorator(view_func):
        def wrapped_view(request, *args, **kwargs):
            # 1. 验证Token逻辑(替换为你的第三方Token验证代码)
            token = request.headers.get('Authorization')
            if not token:
                raise exceptions.AuthenticationFailed('Token缺失')
            
            # 模拟Token验证与角色解析(实际替换为第三方服务调用逻辑)
            is_valid_token = True  # 替换为真实验证结果
            user_roles = ['admin']  # 替换为从Token解析出的角色
            
            if not is_valid_token:
                raise exceptions.AuthenticationFailed('无效Token')
            
            # 2. 检查角色权限
            if not set(user_roles) & set(allowed_roles):
                return Response(
                    {"status": "Failed", "message": "无权限访问"},
                    status=status.HTTP_403_FORBIDDEN
                )
            
            # 验证通过,继续执行视图
            return view_func(request, *args, **kwargs)
        return wrapped_view
    return decorator

步骤2:在DRF视图中使用

from users.decorators import token_and_role_required
from rest_framework.views import APIView
from rest_framework.response import Response
import status

class UserPoolInfo(APIView):
    # 指定允许访问的角色集合
    @token_and_role_required(allowed_roles=['admin', 'editor'])
    def get(self, request):
        user_manager_object = UserManager()
        user_pool_info = user_manager_object.get_user_pool_info()
        response_data = {
            "status":"Success",
            "statusCode": status.HTTP_200_OK,
            "message":"fetched user pool information",
            "data": user_pool_info
        }
        return Response(response_data, status.HTTP_200_OK)

方案三:调整中间件写法兼容装饰器转换

如果你坚持要使用中间件转装饰器,可以给中间件添加process_view方法,让它更适配装饰器的执行逻辑:

# users/middleware.py
class SimpleMiddleware:
    def __init__(self, get_response=None):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        # 在这里编写Token验证、角色检查等前置逻辑
        print(f"inside the custom middleware process_view")
        
        # 验证通过返回None,继续执行视图;验证失败可直接返回Response
        return None

调整后再用decorator_from_middleware转换,配合method_decorator即可在DRF类视图中正常使用。


内容的提问来源于stack exchange,提问作者Redgrave

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 17:50:35