给用户分配角色需显式调用user.groups.add(group_instance);权限绑定须运行makemigrations生成自定义权限,再通过group.permissions.add(perm)添加;@permission_required失效主因是权限字符串错误或用户未加入对应组。
怎么给用户分配角色(Group)
Group 是 Django 权限体系里最轻量、也最常用的角色抽象,它不强制你写模型或继承类,直接复用内置的
模型就行。关键不是“建多少组”,而是“谁在什么场景下改组”——比如后台管理员手动加,注册时自动进默认组,或者通过 API 动态同步。
常见错误是把权限直接塞进 Group 之后就不管了,结果用户登录后
还是返回
:忘了用户得显式加入该 Group。
添加用户到组:
或
(传 ID 也行)
从组移除:
清空所有组:
(注意:这不会删权限,只清组关联)
检查是否在某组:
,比
更可靠(避免缓存/延迟问题)
Permission 怎么绑定到模型和视图
Django 的
默认随每个模型自动生成
、
、
、
四种,但仅当模型定义了
才能扩展自定义项,比如
。
容易踩的坑是:写了
却没跑
—— 自定义权限根本不会进数据库,
会静默失败或报
。
立即学习
“
Python免费学习笔记(深入)
”;
查权限对象:
加权限到组:
视图中判断:
(注意 app_label.codename 格式)
模板中用:
(需确保
已启用)
为什么 @permission_required 有时不生效
看似简单,但失效往往不是装饰器写错了,而是路径或参数没对齐。它默认重定向到
,如果用户已登录却跳转登录页,大概率是权限字符串写错,或者用户根本没被赋予对应权限(包括没加 Group、没同步权限、拼写大小写不一致)。
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
下载
另一个隐蔽问题是:它只检查权限,不检查用户是否活跃(
)或是否为 staff(
在 admin 视图里会额外拦截)。
正确写法:
(加
可避免静默重定向)
函数视图中手动检查:
Class-Based View 推荐用
或
,后者要求设置
别用
替代权限检查——登录 ≠ 有权限
Group 和 Permission 的性能与边界在哪
单次请求里查权限本身开销极小(Django 会缓存
结果),真正拖慢的是频繁调用
并传入不同 app_label 或动态 codename——比如循环里判断每个文章的编辑权限,就会触发多次 DB 查询。
更麻烦的是跨模型权限(如“能编辑自己发布的文章”)无法靠内置 Group+Permission 解决,必须手写逻辑,这时硬套
反而让权限散落在 view、model、template 多处,难维护。
批量查权限建议预加载:
复杂规则(如对象级权限)别强扭内置机制,考虑
或自定义
Group 不支持嵌套,想做“编辑组继承内容组权限”?得手动同步,或换用
这类第三方包
生产环境别用
当权限兜底——它绕过所有权限检查,审计和最小权限原则全失效
权限不是越细越好,关键是哪些操作真需要隔离。比如“删除用户”和“导出报表”权限混在一个 Group 里,后期拆分就会牵连大量已有代码。一开始就把权限 codename 命名清楚、范围划明白,比后期补迁移靠谱得多。
Grouprequest.user.has_perm('blog.delete_post')Falseuser.groups.add(group_instance)user.groups.add(123)user.groups.remove(group_instance)user.groups.clear()user.groups.filter(name='editor').exists()inPermissionadd_change_delete_view_Meta.permissions('publish_post', 'Can publish post')Meta.permissionspython manage.py makemigrationsGroup.permissions.add()Permission matching query does not existfrom django.contrib.auth.models import Permission; perm = Permission.objects.get(codename='publish_post')group.permissions.add(perm)if request.user.has_perm('blog.publish_post'):{% if perms.blog.publish_post %}...{% endif %}context_processors.auth@permission_requiredsettings.LOGIN_URLis_active=Falseis_staff=False@permission_required('blog.change_post', raise_exception=True)raise_exception=Trueif not request.user.has_perm('blog.change_post'): raise PermissionDeniedUserPassesTestMixinPermissionRequiredMixinpermission_required = 'blog.change_post'@login_requireduser.get_all_permissions()user.has_perm()Permissionuser = User.objects.prefetch_related('groups__permissions').get(id=xxx)django-guardianhas_object_permissiondjango-role-permissionsis_superuser=True