Django自定义用户模型创建失败:多类型Profile同步创建问题
问题描述
我正在开发学校管理系统,希望管理员通过自定义User模型创建用户时,同步创建对应不同类型的Profile(如AdminHOD)。但目前用户创建失败,不清楚问题所在,现附上相关代码请求排查问题。
CustomUser模型代码
class CustomUser(AbstractBaseUser, PermissionsMixin): email = models.EmailField(_("email address"), unique=True) first_name = models.CharField(max_length=100, blank=True, null=True) last_name = models.CharField(max_length=100, blank=True, null=True) is_staff = models.BooleanField(default=False) is_active = models.BooleanField(default=True) is_student = models.BooleanField(default=False) is_parent = models.BooleanField(default=False) is_teacher = models.BooleanField(default=False) date_joined = models.DateTimeField(default=timezone.now) USERNAME_FIELD = "email" REQUIRED_FIELDS = ['first_name', 'last_name'] objects = CustomUserManager() def __str__(self): return self.email
AdminHOD模型代码
class AdminHOD(models.Model): user = models.OneToOneField(User, null=True, on_delete=models.CASCADE) title = models.CharField(_('Title'), max_length=4, default=MR, choices=TITLE, blank=False, null=True) bio = models.TextField() gender = models.CharField(_('Gender'), max_length=20, default=MALE, choices=GENDER, blank=False) tel = models.CharField(default='+273240000000', null = False, blank=False, max_length=15, help_text= 'Enter number with Country Code Eg. +273240000000') birthday = models.DateField(_('Birthday'), blank=False, null=False) avatar = models.ImageField(blank=True, null=True, upload_to="avatars/adminhod/") address_line_1 = models.CharField(_('Address Line 1'), max_length=125, null=True, blank=True) address_line_2 = models.CharField(_('Address Line 2'), max_length=125, null=True, blank=True) city = models.CharField(_('City'), max_length=125, null=True, blank=True) province = models.CharField(_('Province'), max_length=40, default=GAUTENG, choices=PROVINCES, blank=False, null=True) created = models.DateTimeField(verbose_name=_('Created'), auto_now_add=True) updated = models.DateTimeField(verbose_name=_('Updated'), auto_now=True) class Meta: verbose_name = _('AdminHOD') verbose_name_plural = _('AdminHODs') ordering = ['-created'] def __str__(self): return str(self.user)
signals.py代码
@receiver(post_save, sender=User) def create_user_profile(sender, instance, created, **kwargs): if created: if instance.is_staff or instance.is_superuser: AdminHOD.objects.update_or_create( user=instance, bio=instance.adminhod.bio, avatar=instance.adminhod.avatar, title=instance.adminhod.title, gender=instance.adminhod.gender, tel=instance.adminhod.tel, birthday=instance.adminhod.birthday, address_line_1=instance.adminhod.address_line_1, address_line_2=instance.adminhod.address_line_2, city=instance.adminhod.city, province=instance.adminhod.province, ) @receiver(post_save, sender=User) def save_profile(sender, instance, **kwargs): if instance.is_staff or instance.is_superuser: instance.adminhod.save()
创建视图代码
def AdminHODCreationView(request): if request.method == 'POST': profile_form = AdminHODForm(request.POST) admin_profile = profile_form.save(commit=False) user_form = CustomUserCreationForm(request.POST) if user_form.is_valid(): user = user_form.save(commit=False) user.admin_profile = admin_profile user.save() email = user.email first_name = user.first_name last_name = user.last_name messages.success(request, f'Account created for {first_name} {last_name} as admin') return redirect('admin_users') else: user_form = CustomUserCreationForm() profile_form = AdminHODForm() context = { 'title': 'Add New Admin', 'user_form': user_form, 'profile_form': profile_form } return render(request, 'adminHOD/add_adminhod.html', context)
问题排查与修复方案
核心问题点
- 模型关联错误:AdminHOD模型中
OneToOneField引用的是默认User模型,而非自定义的CustomUser,导致关联不匹配。 - 信号逻辑错误:信号中尝试访问
instance.adminhod,但此时AdminHOD尚未创建,会触发RelatedObjectDoesNotExist异常;同时update_or_create的参数写法错误,应该用defaults传递字段值。 - 视图逻辑错误:视图中给
user赋值不存在的admin_profile字段,且未将Profile与用户正确关联,导致数据无法保存。
分步修复
1. 修正AdminHOD模型关联
# 导入自定义的CustomUser模型 from .models import CustomUser class AdminHOD(models.Model): # 将关联对象改为CustomUser user = models.OneToOneField(CustomUser, null=True, on_delete=models.CASCADE) # 其余字段保持不变
2. 重构信号逻辑
from django.db.models.signals import post_save from django.dispatch import receiver from .models import CustomUser, AdminHOD @receiver(post_save, sender=CustomUser) def create_user_profile(sender, instance, created, **kwargs): if created: # 为staff或超级用户创建AdminHOD if instance.is_staff or instance.is_superuser: AdminHOD.objects.create(user=instance) @receiver(post_save, sender=CustomUser) def save_profile(sender, instance, **kwargs): # 确保关联的Profile能正常保存,不存在则创建 try: if instance.is_staff or instance.is_superuser: instance.adminhod.save() except AdminHOD.DoesNotExist: AdminHOD.objects.create(user=instance)
3. 修复视图逻辑
def AdminHODCreationView(request): if request.method == 'POST': # 同时处理用户表单和Profile表单,注意处理文件字段 user_form = CustomUserCreationForm(request.POST) profile_form = AdminHODForm(request.POST, request.FILES) if user_form.is_valid() and profile_form.is_valid(): # 先保存用户并标记为staff user = user_form.save(commit=False) user.is_staff = True user.save() # 保存Profile并关联到用户 admin_profile = profile_form.save(commit=False) admin_profile.user = user admin_profile.save() messages.success(request, f'Account created for {user.first_name} {user.last_name} as admin') return redirect('admin_users') else: user_form = CustomUserCreationForm() profile_form = AdminHODForm() context = { 'title': 'Add New Admin', 'user_form': user_form, 'profile_form': profile_form } return render(request, 'adminHOD/add_adminhod.html', context)
4. 额外注意事项
- 在应用的
apps.py的ready()方法中注册信号:import yourapp.signals - 确保
CustomUserCreationForm正确适配自定义User模型 - 模板表单需添加
enctype="multipart/form-data"以支持图片上传
内容的提问来源于stack exchange,提问作者Umar Milanzi Snr
相关产品推荐
相关产品推荐

