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

自定义用户模型场景下Django组与权限的高效管理方案问询

自定义用户模型场景下Django组与权限的高效管理方案问询

我的现有实现背景

我在Django项目里一直习惯用自定义用户模型,通过role字段来控制用户对特定路由的访问权限,代码大概是这样的:

from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
from django.db import models
from django.core.validators import FileExtensionValidator
from enum import Enum

# 先假设USER_ROLES是一个枚举类
class USER_ROLES(Enum):
    ADMIN = "admin"
    EDITOR = "editor"
    VIEWER = "viewer"

class CustomUserManager(BaseUserManager):
    # 这里省略自定义管理器的实现
    pass

class User(AbstractBaseUser, PermissionsMixin):
    name = models.CharField("full name", max_length=255, blank=True)
    email = models.EmailField("email address", unique=True)
    createdAt = models.DateField(auto_now_add=True)
    photo = models.ImageField(
        "profile photo",
        blank=True,
        null=True,
        validators=[
            FileExtensionValidator(allowed_extensions=["jpg", "png", "jpeg"])
        ],
    )
    role = models.CharField(
        max_length=50,
        choices=[(role.value, role.name) for role in USER_ROLES],
    )
    is_active = models.BooleanField(default=True)

    USERNAME_FIELD = "email"
    objects: CustomUserManager = CustomUserManager()

    def has_perm(self, perm, obj=None):
        if self.role == USER_ROLES.ADMIN.value:
            return True
        return super().has_perm(perm, obj)

    def has_module_perms(self, app_label):
        if self.role == USER_ROLES.ADMIN.value:
            return True
        return super().has_module_perms(app_label)

    @property
    def is_staff(self):
        return self.role == USER_ROLES.ADMIN.value

    @property
    def is_superuser(self):
        return self.role == USER_ROLES.ADMIN.value

    def __str__(self) -> str:
        return f"{self.pk}-{self.email}"

现在我意识到为了灵活性,最好切换到多角色模式,打算用Django内置的Group和Permission模型来实现。但我有点困惑:怎么在视图/API路由里处理用户的组和权限?如果之后需要同步组和权限的变更,该怎么做?有没有不依赖Django内置Admin面板的高效方案?

我之前想过在创建用户的视图里每次用Group.get_or_create,再写一个视图来给特定组添加或更新权限,然后用组权限来做授权,但不确定如果之后要修改用户组的话,这种方式是否靠谱。


我的建议方案

我之前也遇到过类似的需求,分享几个实用的思路,亲测在生产环境里挺好用的:

1. 提前初始化核心组与权限(避免重复创建)

不要每次创建用户都调用Group.get_or_create,而是用数据迁移来初始化系统核心组和对应权限,这样能保证组的唯一性,也不会在视图里做重复操作。

比如创建一个迁移文件:

from django.db import migrations
from django.contrib.auth.models import Group, Permission

def create_groups_and_permissions(apps, schema_editor):
    # 创建核心组
    admin_group, _ = Group.objects.get_or_create(name="Admin")
    editor_group, _ = Group.objects.get_or_create(name="Editor")
    viewer_group, _ = Group.objects.get_or_create(name="Viewer")

    # 给组分配权限(比如给Admin组添加所有权限)
    all_permissions = Permission.objects.all()
    admin_group.permissions.add(*all_permissions)

    # 给Editor组添加特定模型的权限,比如文章的增改权限
    article_perms = Permission.objects.filter(codename__in=["add_article", "change_article"])
    editor_group.permissions.add(*article_perms)

    # Viewer组只给查看权限
    viewer_perms = Permission.objects.filter(codename__in=["view_article"])
    viewer_group.permissions.add(*viewer_perms)

class Migration(migrations.Migration):
    dependencies = [
        # 依赖你的用户模型所在app的迁移
        ('your_app', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(create_groups_and_permissions),
    ]

这样系统启动后就有了预设的组和权限,后续只需要维护迁移文件来更新组权限即可,比在视图里处理更可靠。

2. 视图/API中处理用户组的增删改

对于用户组的变更,你可以写专门的API视图(比如用Django REST Framework)来处理,核心是操作user.groups这个多对多关系:

# 示例:给用户添加组的API视图
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import User
from django.contrib.auth.models import Group

class AssignUserGroupView(APIView):
    def post(self, request):
        user_id = request.data.get("user_id")
        group_name = request.data.get("group_name")
        
        try:
            user = User.objects.get(pk=user_id)
            group = Group.objects.get(name=group_name)
            # 替换用户所有组(如果是追加用user.groups.add(group))
            user.groups.set([group])
            user.save()
            return Response({"message": "用户组已更新"}, status=status.HTTP_200_OK)
        except User.DoesNotExist:
            return Response({"error": "用户不存在"}, status=status.HTTP_404_NOT_FOUND)
        except Group.DoesNotExist:
            return Response({"error": "组不存在"}, status=status.HTTP_404_NOT_FOUND)

如果需要支持多组,只需要把group_name改成group_names列表,然后循环添加或者用set()方法批量设置就行。

3. 权限校验的实现

切换到组权限后,你可以用Django内置的权限装饰器或者自定义权限类来做校验:

  • 函数视图可以用@permission_required装饰器,比如:
    from django.contrib.auth.decorators import permission_required
    
    @permission_required("your_app.view_article", raise_exception=True)
    def article_list(request):
        # 视图逻辑
        pass
    
  • 类视图(DRF)可以用permission_classes:
    from rest_framework.permissions import IsAuthenticated, DjangoModelPermissions
    from rest_framework.viewsets import ModelViewSet
    from .models import Article
    from .serializers import ArticleSerializer
    
    class ArticleViewSet(ModelViewSet):
        queryset = Article.objects.all()
        serializer_class = ArticleSerializer
        permission_classes = [IsAuthenticated, DjangoModelPermissions]
    

DjangoModelPermissions会自动根据用户所在组的权限来控制对模型的增删改查操作,非常省心。

4. 权限变更的同步

如果之后需要批量更新组的权限,直接修改迁移文件或者写一个管理命令来执行,比如:

# 管理命令示例:更新Editor组的权限
from django.core.management.base import BaseCommand
from django.contrib.auth.models import Group, Permission

class Command(BaseCommand):
    help = "更新Editor组的权限"

    def handle(self, *args, **options):
        editor_group = Group.objects.get(name="Editor")
        # 移除旧权限
        old_perms = Permission.objects.filter(codename="delete_article")
        editor_group.permissions.remove(*old_perms)
        # 添加新权限
        new_perms = Permission.objects.filter(codename="publish_article")
        editor_group.permissions.add(*new_perms)
        self.stdout.write(self.style.SUCCESS("Editor组权限已更新"))

这样比手动在Admin里改更可控,也方便版本控制。


总结一下

  • 用迁移文件初始化组和权限,避免重复创建
  • 写专门的视图/API来处理用户组的分配与变更
  • 利用Django内置的权限校验工具替代自己写的role判断
  • 用管理命令来批量同步权限变更

这种方式既灵活又能保证系统的一致性,完全不需要依赖Admin面板就能搞定所有权限管理操作。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 09:23:07