自定义用户模型注册遇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
相关产品推荐
相关产品推荐

