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
相关产品推荐
相关产品推荐

