Django自定义用户模型实现合法性及优化建议咨询
Django自定义用户模型与角色关联Profile的代码审查与优化建议
作为编程新手,我重写了Django默认用户模型,将用户Profile与CustomUser关联,通过信号接收器在用户创建时根据角色自动生成对应Profile实例,以下是我的代码:
from django.db import models from django.contrib.auth.models import AbstractUser from django.dispatch import receiver from django.utils.translation import gettext_lazy as _ from .managers import CustomUserManager from django.db.models.signals import post_save # Create your models here. class CustomUser(AbstractUser): username = None email = models.EmailField(_("email"),primary_key=True,unique=True,blank=False,null=False) phone_number = models.CharField(max_length=10,null=False,blank=False) ROLE_CHOICES = ( ('ADMIN', 'ADMIN'), ('STUDENT','STUDENT'), ('TEACHER', 'TEACHER'), ('PRINCIPAL', 'PRINCIPAL'), ) role = models.CharField(choices=ROLE_CHOICES, blank=True,default='ADMIN',max_length=10) REQUIRED_FIELDS = ['phone_number','first_name','last_name'] USERNAME_FIELD = "email" objects = CustomUserManager() def __str__(self): return self.email class StudentProfile(models.Model): user = models.OneToOneField(CustomUser,on_delete=models.CASCADE) id = models.AutoField(primary_key=True,unique=True) merit = models.CharField(max_length=6,blank=True,null=True) def __str__(self): return self.user.email class TeacherProfile(models.Model): user = models.OneToOneField(CustomUser,on_delete=models.CASCADE) id = models.AutoField(primary_key=True,unique=True) salary = models.CharField(max_length=6,blank=True,null=True) education = models.CharField(max_length=100,blank=True,null=True) def __str__(self): return self.user.email class PrincipalProfile(models.Model): user = models.OneToOneField(CustomUser,on_delete=models.CASCADE) id = models.AutoField(primary_key=True,unique=True) salary = models.CharField(max_length=6,blank=True,null=True) education = models.CharField(max_length=100,blank=True,null=True) years_of_experience = models.IntegerField(null=True, blank=True) def __str__(self): return self.user.email @receiver(post_save, sender=CustomUser) def create_user_profile(sender, instance, created, **kwargs): if created: if instance.role == 'PRINCIPAL': PrincipalProfile.objects.create(user=instance) elif instance.role == 'STUDENT': StudentProfile.objects.create(user=instance) elif instance.role == 'TEACHER': TeacherProfile.objects.create(user=instance) else: pass else: print("Profile not created")
合法性审查
整体实现逻辑是合法的:
- 继承
AbstractUser自定义用户模型是Django官方推荐的扩展用户模型方式 - 使用
OneToOneField关联不同角色的Profile模型,符合一对一关联的业务逻辑 post_save信号自动创建Profile的思路,是Django中实现用户与档案联动的常规方案- 自定义用户模型的
USERNAME_FIELD、REQUIRED_FIELDS配置正确,管理器引入也符合规范(假设CustomUserManager实现无误)
优化建议
1. 角色字段规范化
- 用Django内置的
TextChoices枚举类替代元组选项,避免硬编码字符串,同时支持国际化:from django.db.models import TextChoices class RoleChoices(TextChoices): ADMIN = 'ADMIN', _('ADMIN') STUDENT = 'STUDENT', _('STUDENT') TEACHER = 'TEACHER', _('TEACHER') PRINCIPAL = 'PRINCIPAL', _('PRINCIPAL') - 角色字段设置
blank=False,因为已有默认值ADMIN,避免出现空值:role = models.CharField(choices=RoleChoices.choices, default=RoleChoices.ADMIN, max_length=10, blank=False)
2. Profile模型简化与字段优化
- 删除手动定义的
id = models.AutoField(primary_key=True,unique=True),Django会自动为每个模型生成自增主键,无需重复定义 - 薪资字段
salary改用DecimalField(数值类型)替代CharField,方便后续计算、排序:salary = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True) - 为
OneToOneField添加related_name,方便从用户反向查询关联档案:
之后可以通过user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, related_name='student_profile')user.student_profile快速获取学生档案,无需额外查询。
3. 信号接收器优化
- 移除
else分支的print("Profile not created"),生产环境中print输出无意义,且用户更新时本就无需创建Profile - 用字典映射替代多分支
if-elif,让代码更简洁易维护:PROFILE_MAP = { RoleChoices.PRINCIPAL: PrincipalProfile, RoleChoices.STUDENT: StudentProfile, RoleChoices.TEACHER: TeacherProfile, } @receiver(post_save, sender=CustomUser, dispatch_uid='create_user_profile_signal') def create_user_profile(sender, instance, created, **kwargs): if created: profile_class = PROFILE_MAP.get(instance.role) if profile_class: profile_class.objects.create(user=instance) - 添加
dispatch_uid参数,避免信号因重复导入而重复注册
4. 细节完善
- 给字段添加清晰的
verbose_name,优化后台管理界面的显示:phone_number = models.CharField(_("phone number"), max_length=10, null=False, blank=False) - 给手机号添加格式验证,确保输入符合要求:
from django.core.validators import RegexValidator phone_regex = RegexValidator( regex=r'^[0-9]{10}$', message="Phone number must be exactly 10 digits." ) phone_number = models.CharField( _("phone number"), max_length=10, null=False, blank=False, validators=[phone_regex] ) - 若需要支持用户角色变更时同步更新Profile,可在信号中处理
created=False的情况,比如删除旧Profile并创建新的对应档案
内容的提问来源于stack exchange,提问作者Mr. Devloper_0310
相关产品推荐
相关产品推荐

