Django默认的user.is_authenticated仅验证登录状态,无法满足细粒度权限控制需求;需结合Group、Permission及自定义逻辑实现模型级与对象级权限校验,并确保permissions在Meta中声明、迁移生成且正确绑定。

为什么直接用 user.is_authenticated 不够用
因为登录只是第一道门槛,真实业务里常需要区分“谁可以删订单”“谁只能看自己提交的工单”。Django 自带的 Group 和 Permission 模型不是摆设——它们被设计成可组合、可复用的权限单元,但默认不自动关联到视图或模板中,得手动接入。
常见错误是只给用户加 Group,却没在视图里检查对应权限;或者用了 @permission_required,但没同步注册自定义模型权限(比如 myapp.add_report),结果始终 403。
- 确保每个需要权限控制的模型,在
Meta类中声明permissions(如('can_export', 'Can export report')),否则manage.py migrate不会生成对应权限记录 -
Group本身不带逻辑,必须通过group.permissions.add(perm)或管理后台显式绑定权限 - 用户加入多个
Group时,权限是并集,不是交集——这点常被误以为“角色互斥”
如何在 CBV 中正确检查对象级权限
PermissionRequiredMixin 只能做模型级(如 blog.delete_post),对“只允许作者删除自己的文章”这种需求无效。此时要重写 dispatch() 或使用 get_object() 预校验。
示例:一个编辑视图,要求用户要么是超级用户,要么是文章作者,且拥有 blog.change_post 权限:
立即学习“Python免费学习笔记(深入)”;
class PostUpdateView(PermissionRequiredMixin, UpdateView):
model = Post
fields = ['title', 'content']
permission_required = 'blog.change_post'
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
if not (request.user.is_superuser or obj.author == request.user):
raise PermissionDenied
return super().dispatch(request, *args, **kwargs)
- 别把对象级逻辑全塞进
has_permission()——它只接收request和view,拿不到self.get_object() - 如果频繁用同类逻辑,建议抽成 mixin,但注意和
PermissionRequiredMixin的调用顺序:mixin 必须在它前面,否则dispatch被拦截太早 - 模板中用
{% if perms.blog.change_post %}仅判断模型级权限,不校验对象归属——仍需后端兜底
怎么让 Group 名称和前端角色名解耦
管理后台显示的 Group.name(如 'editor')不该直接暴露给前端或日志。用户看到的是“编辑员”,系统内部用的是机器可读标识符。
推荐做法:在 Group 上扩展字段,或用约定前缀隔离语义:
- 创建 Group 时用下划线分隔层级:
'role_editor'、'role_reviewer',避免和未来可能的权限 codename 冲突(如'editor_can_publish') - 在用户 Profile 或中间表里存
display_name,而非依赖Group.name - 权限查询时统一用
user.has_perm('blog.publish_post'),而不是user.groups.filter(name='editor')——后者绕过权限系统,无法响应权限变更
迁移后权限没生效?先查 auth_permission 表
运行 python manage.py migrate 后,新模型的权限不会自动出现在数据库。必须执行 python manage.py migrate + python manage.py createcachetable(如果用了缓存权限)之后,再确认 auth_permission 表是否包含你定义的权限行。
调试技巧:
- 在 shell 中运行
from django.contrib.auth.models import Permission; Permission.objects.filter(codename__contains='export'),看是否返回预期记录 - 检查
ContentType是否已为你的模型创建:权限依赖ContentType关联模型,若模型刚添加且未迁移,Permission无法绑定 - 清除权限缓存:如果用了
django.contrib.auth.backends.ModelBackend默认配置,权限是实时查库的;但某些自定义 backend 或中间件可能缓存了结果,重启 Django 进程最稳妥
权限链越长(Group → Permission → Model → View → Template),漏掉一环就失效。最常被跳过的其实是 ContentType 的存在性验证和权限 codename 的拼写一致性——大小写、下划线、复数形式都得和 Meta.permissions 完全一致。


















