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

Django用户权限管控:非超级用户的分组管理员需求实现

解决Django Admin中角色A的权限限制问题

我刚好在项目里处理过几乎一模一样的多角色权限场景,给你一套最简的原生Django实现方案,不用额外装第三方库,核心是通过自定义ModelAdmin的几个钩子来锁死权限边界:


1. 锁定User模型的敏感操作

首先要杜绝角色A修改is_superuser这类敏感权限,同时限制他们只能看到同D值的用户。我们重写默认的UserAdmin:

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .models import User

class CustomUserAdmin(BaseUserAdmin):
    # 控制不同角色能看到的字段组
    def get_fieldsets(self, request, obj=None):
        fieldsets = super().get_fieldsets(request, obj)
        # 当前用户是角色A且不是超级用户时,隐藏超级用户权限字段
        if request.user.is_appadmin and not request.user.is_superuser:
            # 移除包含is_superuser的字段组(默认在"Permissions"分组里)
            fieldsets = [
                (name, opts) for name, opts in fieldsets 
                if 'is_superuser' not in opts.get('fields', [])
            ]
            # 只允许角色A修改B、C类角色的标识字段
            fieldsets.append(("用户角色", {"fields": ("is_appuser", "is_someuser")}))
        return fieldsets

    # 限制角色A只能查看同D值的用户
    def get_queryset(self, request):
        qs = super().get_queryset(request)
        if request.user.is_appadmin and not request.user.is_superuser:
            # 替换成你实际的User与D模型的多对多关联字段(比如user.ds)
            return qs.filter(d__in=request.user.d_set.all())
        return qs

    # 强制控制角色A创建用户的权限
    def save_model(self, request, obj, form, change):
        if request.user.is_appadmin and not request.user.is_superuser:
            # 彻底锁死超级用户权限,无论表单提交什么都设为False
            obj.is_superuser = False
            # 如果创建的是C类用户,自动赋予后台访问权限(假设用is_staff字段)
            if obj.is_someuser:
                obj.is_staff = True
            # 自动关联当前角色A的D值给新创建的用户
            obj.d_set.set(request.user.d_set.all())
        super().save_model(request, obj, form, change)

2. 限制分组的多对多操作权限

接下来处理角色A只能将同D值的C类用户添加到同D值分组的需求,重写GroupAdmin:

from django.contrib.auth.models import Group

class CustomGroupAdmin(admin.ModelAdmin):
    # 控制分组选择用户时的可选范围
    def formfield_for_manytomany(self, db_field, request, **kwargs):
        if db_field.name == "user_set" and request.user.is_appadmin and not request.user.is_superuser:
            # 只显示同D值的C类用户
            kwargs["queryset"] = User.objects.filter(
                is_someuser=True,
                d__in=request.user.d_set.all()
            )
        return super().formfield_for_manytomany(db_field, request, **kwargs)

    # 限制角色A只能查看同D值的分组
    def get_queryset(self, request):
        qs = super().get_queryset(request)
        if request.user.is_appadmin and not request.user.is_superuser:
            return qs.filter(d__in=request.user.d_set.all())
        return qs

3. 注册自定义Admin并分配基础权限

最后替换默认的Admin注册:

# 先注销默认的User和Group Admin
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)

admin.site.unregister(Group)
admin.site.register(Group, CustomGroupAdmin)

然后在Django后台的权限管理里,给角色A对应的用户组分配以下权限:

  • 用户模型的添加、更改、删除权限
  • 分组模型的更改权限
  • 后台访问权限(确保角色A用户的is_staff字段为True)

关键注意点

  • 代码里的d_set要替换成你实际项目中User与D模型的多对多关联字段名(比如如果关联字段是ds,就改成ds.all())
  • 如果你的后台访问权限不是用is_staff,替换成你项目里对应的字段即可
  • 这套方案完全用Django原生功能实现,没有额外依赖,是最轻量化的解决方案

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 17:12:50