Django Rest Framework中创建关联Profile的用户模型时的属性错误修复
我想在Serializer的create方法中创建关联Profile的User实例,预期接收name、email和password三个输入字段:
email和password用于创建User实例name和User实例用于创建Profile实例
我在UserRegisterSerializer中指定模型为自定义User模型,并额外定义了User模型没有的name字段。在create方法中,我从验证数据中弹出name,用email和password创建User,再用该User和name创建Profile。
但测试创建用户时触发以下错误:
AttributeError at /api/users/register/
Got AttributeError when attempting to get a value for fieldnameon serializerUserRegisterSerializer.
The serializer field might be named incorrectly and not match any attribute or key on theUsersinstance.
The original exception text was: 'Users' object has no attribute 'name'.
我困惑的是,我并没有主动去获取name字段的值,请问该如何修复?
相关代码
Views.py
class UserRegisterAPIView(CreateAPIView): queryset = User.objects.all() serializer_class = UserRegisterSerializer
Models.py
Users:自定义用户模型,包含id、email、password等字段Profiles:与Users为一对一关联,包含user、name等字段
Serializers.py
User = get_user_model() class ProfileSerializer(serializers.ModelSerializer): class Meta: model = Profiles fields = '__all__' class UserRegisterSerializer(serializers.ModelSerializer): class Meta: model = User fields = ('name', 'email', 'password') name = serializers.CharField(max_length=255, required=True) email = serializers.EmailField( required=True, validators=[UniqueValidator(queryset=User.objects.all())], ) password = serializers.CharField( write_only=True, required=True, style={'input_type': 'password'}, validators=[validate_password], ) def create(self, validated_data): name = validated_data.pop('name') # 创建用户 user = User.objects.create_user( validated_data['email'], ) # 设置密码并保存 user.set_password(validated_data['password']) user.save() # 创建关联的Profile profile = Profiles.objects.create( user=user, name=name ) profile.save() return user
错误的核心原因是:
UserRegisterSerializer继承自ModelSerializer,且在Meta.fields中包含了name字段- 当
create方法返回user实例后,Serializer会自动序列化这个实例生成响应数据 - 序列化过程中,Serializer会尝试从
user实例中读取name字段的值,但你的Users模型并没有这个字段,因此触发AttributeError
方案一:给name字段添加write_only=True
这是最直接的解决方法,告诉Serializername字段只用于接收输入,不参与返回结果的序列化:
name = serializers.CharField(max_length=255, required=True, write_only=True)
方案二:优化create_user调用(可选)
你的create_user调用可以简化,因为create_user方法本身支持直接传入密码并自动哈希,不需要额外调用set_password:
def create(self, validated_data): name = validated_data.pop('name') # 直接用关键字参数传递email和password,create_user自动处理密码哈希 user = User.objects.create_user( email=validated_data['email'], password=validated_data['password'] ) # 创建Profile(无需单独调用save(),create方法会自动保存) Profiles.objects.create(user=user, name=name) return user
方案三:返回包含Profile的序列化数据(可选)
如果你希望返回的响应中包含Profile信息,可以添加嵌套Serializer并刷新用户实例:
class UserRegisterSerializer(serializers.ModelSerializer): name = serializers.CharField(max_length=255, required=True, write_only=True) profile = ProfileSerializer(read_only=True) # 添加嵌套的ProfileSerializer class Meta: model = User fields = ('name', 'email', 'password', 'profile') # ... 其他字段定义 ... def create(self, validated_data): name = validated_data.pop('name') user = User.objects.create_user(**validated_data) Profiles.objects.create(user=user, name=name) # 刷新user实例,确保关联的profile被加载 user.refresh_from_db() return user
内容的提问来源于stack exchange,提问作者Mark Han

