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

Django模型级权限与多角色用户设计问题咨询

解决方案指引

一、让角色实例直接成为系统用户

推荐两种实现方式,均满足“角色实例本身就是合法系统用户”的需求:

方式1:多表继承(最贴合你的需求)

基于Django的AbstractUser创建基础用户模型,让Teacher、Student、Manager直接继承该模型,这样每个角色实例同时拥有系统用户的核心属性(如username、password、email)和自身专属字段:

# models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class BaseUser(AbstractUser):
    # 可添加所有角色共享的字段,比如手机号
    phone = models.CharField(max_length=11, blank=True)

class Teacher(BaseUser):
    # 教师专属字段
    subject = models.CharField(max_length=50, verbose_name="任教科目")
    clazz = models.ForeignKey("Class", on_delete=models.CASCADE, verbose_name="所带班级")

class Student(BaseUser):
    # 学生专属字段
    avg_grade = models.FloatField(default=0.0, verbose_name="平均成绩")
    clazz = models.ForeignKey("Class", on_delete=models.CASCADE, verbose_name="所在班级")

class Manager(BaseUser):
    # 管理员专属字段
    department = models.CharField(max_length=50, verbose_name="所属部门")

在settings.py中指定自定义用户模型:

AUTH_USER_MODEL = "你的应用名.BaseUser"

创建Teacher/Student/Manager实例时,直接填写用户属性(如username、password)和专属字段即可,无需先创建基础用户再关联,实例本身就是可登录的系统用户。

方式2:自定义用户模型+自动关联Profile(更灵活)

若不想用多表继承,可创建单一基础用户模型,通过OneToOneField关联不同角色的Profile,并用Django信号自动生成Profile:

# models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver

class CustomUser(AbstractUser):
    ROLE_CHOICES = (
        ('TEACHER', '教师'),
        ('STUDENT', '学生'),
        ('MANAGER', '管理员'),
    )
    role = models.CharField(max_length=10, choices=ROLE_CHOICES, verbose_name="角色")

class TeacherProfile(models.Model):
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, related_name="teacher_profile")
    subject = models.CharField(max_length=50)
    clazz = models.ForeignKey("Class", on_delete=models.CASCADE)

class StudentProfile(models.Model):
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, related_name="student_profile")
    avg_grade = models.FloatField(default=0.0)
    clazz = models.ForeignKey("Class", on_delete=models.CASCADE)

class ManagerProfile(models.Model):
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, related_name="manager_profile")
    department = models.CharField(max_length=50)

# 信号:创建用户时自动生成对应Profile
@receiver(post_save, sender=CustomUser)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        if instance.role == 'TEACHER':
            TeacherProfile.objects.create(user=instance)
        elif instance.role == 'STUDENT':
            StudentProfile.objects.create(user=instance)
        elif instance.role == 'MANAGER':
            ManagerProfile.objects.create(user=instance)

创建用户时选择角色,系统自动生成对应Profile,用户本身是系统用户,专属字段存储在Profile中。

二、高效判断用户角色类型

针对多表继承方案

利用Django对象缓存,通过hasattr快速判断,避免重复查询数据库:

# 在BaseUser模型中添加属性方法
class BaseUser(AbstractUser):
    # ... 其他字段
    @property
    def role(self):
        if hasattr(self, 'teacher'):
            return 'TEACHER'
        elif hasattr(self, 'student'):
            return 'STUDENT'
        elif hasattr(self, 'manager'):
            return 'MANAGER'
        return 'UNKNOWN'

使用时直接调用request.user.role即可获取角色类型。

针对自定义用户+Profile方案

直接读取用户表的role字段,无需查询关联表:

role = request.user.role  # 直接返回TEACHER/STUDENT/MANAGER

需要获取专属字段时,通过反向关联快速获取:

if request.user.role == 'TEACHER':
    subject = request.user.teacher_profile.subject

三、权限控制实现思路

结合Django REST Framework的权限类或自定义逻辑,根据角色过滤数据:

自定义权限类(复用性强)

from rest_framework.permissions import BasePermission

class IsStudent(BasePermission):
    def has_permission(self, request, view):
        return hasattr(request.user, 'student')  # 多表继承方案
        # 或 return request.user.role == 'STUDENT'  # Profile方案

class IsTeacher(BasePermission):
    def has_permission(self, request, view):
        return hasattr(request.user, 'teacher')

class IsManager(BasePermission):
    def has_permission(self, request, view):
        return hasattr(request.user, 'manager')

视图中实现权限逻辑

# 学生查看自身成绩
class StudentGradeView(APIView):
    permission_classes = [IsStudent]
    def get(self, request):
        grades = Grade.objects.filter(student=request.user)
        serializer = GradeSerializer(grades, many=True)
        return Response(serializer.data)

# 教师查看所带班级学生
class TeacherClassStudentsView(APIView):
    permission_classes = [IsTeacher]
    def get(self, request):
        students = Student.objects.filter(clazz=request.user.clazz)
        serializer = StudentSerializer(students, many=True)
        return Response(serializer.data)

# 管理员查看所有数据
class ManagerAllDataView(APIView):
    permission_classes = [IsManager]
    def get(self, request):
        students = Student.objects.all()
        teachers = Teacher.objects.all()
        return Response({
            "students": StudentSerializer(students, many=True).data,
            "teachers": TeacherSerializer(teachers, many=True).data
        })

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 00:25:30