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

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)

问题排查与修复方案

核心问题点

  1. 模型关联错误:AdminHOD模型中OneToOneField引用的是默认User模型,而非自定义的CustomUser,导致关联不匹配。
  2. 信号逻辑错误:信号中尝试访问instance.adminhod,但此时AdminHOD尚未创建,会触发RelatedObjectDoesNotExist异常;同时update_or_create的参数写法错误,应该用defaults传递字段值。
  3. 视图逻辑错误:视图中给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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 19:05:08