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

自定义用户模型注册遇AttributeError:Parent实例无username属性

问题分析与解决

核心错误点

  • 序列化对象类型不匹配:ParentSerializer的create方法最终返回的是Parent实例,但视图中用面向User模型的UserRegistrationSerializer去序列化该对象,导致字段匹配失败。
  • 序列化器冗余定义枚举:UserRegistrationSerializer中重复定义RoleType,未复用User模型中已有的枚举类。
  • 反向关联命名冲突:Parent模型中OneToOneField的related_name="user"与字段名重复,易引发混淆。
  • 视图queryset不匹配:视图使用ParentSerializer,但queryset设为User.objects.all(),不符合DRF规范。

修复代码

1. 修正UserRegistrationSerializer

from .models import User

class UserRegistrationSerializer(serializers.ModelSerializer):
    # 直接复用User模型中的RoleType枚举
    role = serializers.ChoiceField(choices=User.RoleType.choices, default=User.RoleType.PARENT)
    
    class Meta:
        model = User
        fields = ['user_name', 'password', 'email', 'role']
        extra_kwargs = {
            'password': {'write_only': True},
            'email': {'required': True},
            'user_name': {'required': True}
        }

    def create(self, validated_data):
        user = User.objects.create_user(**validated_data)
        return user

2. 修正ParentSerializer的create方法

让方法返回User实例,适配后续序列化逻辑:

class ParentSerializer(serializers.ModelSerializer):
    user = UserRegistrationSerializer(write_only=True)

    class Meta:
        model = Parent
        fields = ['Parental_code', 'user']

    def create(self, validated_data):
        user_data = validated_data.pop('user')
        user = User.objects.create_user(**user_data)
        # 创建Parent关联记录,但返回User实例用于序列化
        Parent.objects.create(user=user, **validated_data)
        return user

3. 修正Parent模型的反向关联命名

class Parent(models.Model):
    Parental_code = models.CharField(max_length=10, unique=True)
    # 修改related_name避免命名冲突
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="parent_profile", null=True)

4. 修正视图逻辑与queryset

class UserRegistrationView(generics.CreateAPIView):
    # 匹配ParentSerializer的queryset
    queryset = Parent.objects.all()
    serializer_class = ParentSerializer
    permission_classes = [permissions.AllowAny]

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.save()
        response_data = UserRegistrationSerializer(user).data
        # 可选:添加Parent信息到响应
        response_data['parental_code'] = Parent.objects.get(user=user).Parental_code
        return Response(response_data, status=status.HTTP_201_CREATED)

额外检查:确保UserManager正确实现

自定义用户模型必须配套正确的管理器,处理user_name而非默认username:

class UserManager(BaseUserManager):
    def create_user(self, user_name, email, password=None, **extra_fields):
        if not user_name:
            raise ValueError('必须设置用户名')
        if not email:
            raise ValueError('必须设置邮箱')
        email = self.normalize_email(email)
        user = self.model(user_name=user_name, email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, user_name, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        return self.create_user(user_name, email, password, **extra_fields)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 18:44:54