Django ListView使用method_decorator报缺少request参数错误
问题现象
Django项目开发中,给类视图方法添加自定义权限装饰器后,运行触发报错:_wrapped_view() missing 1 required positional argument: 'request'
该装饰器在普通函数视图场景下使用无异常,触发报错的原代码如下:
class AudienceListView(ListView): model = Audience template_name = 'audience/list.html' @method_decorator(company_user_has_permission('audiences_view')) def get_queryset(self): queryset = super().get_queryset() company = Company.get_current(self.request) return queryset.filter(company=company) \ .annotate(total_deals=Count("deals"), total_contacts=Count("contacts")) \ .order_by('-id')
报错根因
用于权限校验的视图装饰器,默认会从被装饰方法的第一个位置参数获取request请求对象。
把装饰器直接加在get_queryset方法上存在两个问题:
- 类实例方法的第一个位置参数永远是类实例本身
self,不是request get_queryset是类视图内部被调度调用的辅助方法,不是直接接收请求的入口方法
装饰器运行时把self错当成request读取,自然会提示缺少必填的request位置参数。
修复方案
权限类装饰器需要加在类视图的请求入口方法上,不要加在内部辅助方法上,两种标准写法任选其一即可:
- 写法1:类层面装饰,指定作用于dispatch入口方法
from django.utils.decorators import method_decorator @method_decorator(company_user_has_permission('audiences_view'), name='dispatch') class AudienceListView(ListView): model = Audience template_name = 'audience/list.html' def get_queryset(self): queryset = super().get_queryset() company = Company.get_current(self.request) return queryset.filter(company=company) \ .annotate(total_deals=Count("deals"), total_contacts=Count("contacts")) \ .order_by('-id')
- 写法2:重写dispatch方法,在方法上加装饰器
from django.utils.decorators import method_decorator class AudienceListView(ListView): model = Audience template_name = 'audience/list.html' @method_decorator(company_user_has_permission('audiences_view')) def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs) def get_queryset(self): queryset = super().get_queryset() company = Company.get_current(self.request) return queryset.filter(company=company) \ .annotate(total_deals=Count("deals"), total_contacts=Count("contacts")) \ .order_by('-id')
调整后装饰器可以正确从入口方法的第一个位置参数拿到request对象完成权限校验,代码可正常运行。
内容的提问来源于stack exchange,提问作者jake
相关产品推荐
相关产品推荐

