@permission_required仅校验模型级权限,无法验证“资源归属”或“业务规则”,如编辑文章需确认request.user == article.author;应分层协作:外层用@permission_required兜底模型权限,内层用自定义装饰器或模型方法(如can_edit)执行对象级与业务逻辑校验,确保权限规则可持续演进。

为什么 @permission_required 不够用?
它只能校验用户是否拥有某个权限,无法判断“当前请求的资源是否属于该用户”或“是否满足业务规则”。比如:编辑文章时,需要确认 request.user == article.author,而不仅仅是是否有 blog.change_article 权限。这时候硬套 @permission_required 会绕过业务逻辑,甚至导致越权。
如何写一个带对象级校验的装饰器?
核心是把视图函数的参数(尤其是 pk 或 slug)取出来,查出对应对象,再执行自定义判断。不要在装饰器里直接写 SQL 或重复模型逻辑——复用模型方法或自定义 manager 更可靠。
- 用
*args, **kwargs捕获视图参数,从kwargs中提取主键字段(如kwargs.get('pk')) - 用
get_object_or_404()获取对象,避免裸查引发DoesNotExist - 校验失败时统一返回
HttpResponseForbidden,别用raise PermissionDenied—— 它依赖handler403配置,容易漏配 - 示例:
def owner_required(model_class, owner_field='author'): def decorator(view_func): def _wrapped_view(request, *args, **kwargs): obj = get_object_or_404(model_class, pk=kwargs['pk']) if getattr(obj, owner_field) != request.user: return HttpResponseForbidden() return view_func(request, *args, **kwargs) return _wrapped_view return decorator
装饰器和 Django 自带权限系统怎么协作?
别二选一,要分层:装饰器做对象级 + 业务规则校验,PermissionRequiredMixin 或 @permission_required 做模型级基础权限兜底。比如删除操作,先用 @permission_required('blog.delete_article') 确保用户有删除权限,再用自定义装饰器确认 obj.author == request.user。
- 顺序很重要:把模型级权限装饰器放在外层,对象级装饰器放内层,避免无权限用户触发数据库查询
- 如果用了类视图,优先考虑
dispatch()方法拦截,比装饰器更易测试、更符合 Django 习惯 - 注意缓存影响:如果对象字段(如
status)参与权限判断,且被缓存了,校验可能失效
为什么基于类的权限检查比装饰器更可持续?
装饰器写多了会散落在各处,难以统一审计和修改。把权限逻辑收口到模型的 has_permission_for() 方法或独立的 PermissionChecker 类里,视图中只调用一次,后续加条件(比如“草稿状态下仅作者可编辑”)就不用改所有装饰器。
立即学习“Python免费学习笔记(深入)”;
- 模型上定义:
def can_edit(self, user): return self.author == user and self.status != 'published' - 视图中简洁调用:
if not article.can_edit(request.user): return HttpResponseForbidden() - 这种写法对单元测试友好,也方便前端 API 返回
{ "can_edit": false }字段
真正难的不是写一个能跑的装饰器,而是让权限规则随业务演进不腐化——把判断逻辑从 HTTP 层下沉到领域模型,比堆砌装饰器靠谱得多。


















