DRF 在尝试发布数据时出现 AttributeError

问题描述 投票:0回答:1

我正在 DRF 中使用 Profile 模型创建用户注册 API,该模型与 Django 的默认用户模型具有 OneToOne 关系。我使用 User 模型创建了一个序列化器,并将 Profile 的字段定义为序列化器字段。

问题是当我发布数据时,尽管用户和配置文件保存在数据库中,但我收到此错误


error AttributeError at /auth/registration Got AttributeError when attempting to get a value for field address on serializer UserRegistrationSerializer. The serializer field might be named incorrectly and not match any attribute or key on the User instance. Original exception text was: 'User' object has no attribute 'address'.

使用 write_only

address
似乎可以解决问题,但我想了解为什么会发生这种情况,以及此视图如何访问此地址字段,为什么它忽略
phone_number
date_of_birth
并且不会给我错误那些。任何输入都会有帮助。谢谢!

这是我的代码。

模型.py

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    date_of_birth = models.DateField(null=True)
    phone_number = models.CharField(null=True, max_length=30)
    address = models.CharField(max_length=250)

    def __str__(self):
        return f'Profile of {self.user.username}'

序列化器.py

class UserRegistrationSerializer(serializers.ModelSerializer):
    phone_number = serializers.CharField(required=False, max_length=30)
    date_of_birth = serializers.DateField(required=False)
    address = serializers.CharField(max_length=250)

    password = serializers.CharField(write_only=True)
    password2 = serializers.CharField(write_only=True, label = 'Confirm Password')
    class Meta:
        model = User
        fields = ['username', 'first_name', 'last_name', 'email', 'phone_number', 'date_of_birth', 'address', 'password', 'password2']

    def create(self, validated_data):
        phone_number = validated_data.pop('phone_number', None)
        date_of_birth = validated_data.pop('date_of_birth', None)
        address = validated_data.pop('address', None)
        password = validated_data.pop('password', None)
        first_name = validated_data.pop('first_name', None)
        last_name = validated_data.pop('last_name', None)

        user = User (
            username = validated_data['username'],
            email = validated_data['email'],
            first_name = first_name,
            last_name = last_name
            )

        user.set_password(password)
        user.save()

        Profile.objects.create(
            user=user,
            date_of_birth=date_of_birth,
            address=address,
            phone_number=phone_number
        )

        return user

视图.py

class UserRegistrationView(generics.CreateAPIView):
    serializer_class = UserRegistrationSerializer
    queryset = User.objects.all()
python django django-models django-rest-framework
1个回答
0
投票

出现此错误的原因是没有属于用户的电话号码、出生日期和地址,因此 DRF 无法访问它们。 但是当您放置

write_only=True
时,DRF 不再尝试访问它们,这就是为什么 write_only 似乎解决了问题。

您可以创建nester序列化器

ProfileSerializer
并在您的
UserRegistrationSerializer
中使用它:

class ProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = Profile
        fields = ['date_of_birth','phone_number','address']


class UserRegistrationSerializer(serializers.ModelSerializer):
    profile = ProfileSerializer(required=True)
    password = serializers.CharField(write_only=True)
    password2 = serializers.CharField(write_only=True, label='Confirm Password')

    class Meta:
        model = User
        fields = ['username', 'first_name', 'last_name', 'email', 'password', 'password2', 'profile']

    def create(self, validated_data):
        profile_data = validated_data.pop('profile')
        password = validated_data.pop('password')
        user = User.objects.create(**validated_data)
        user.set_password(password)
        user.save()
        Profile.objects.create(
            user=user,
            date_of_birth=profile_data.get('date_of_birth'),
            phone_number=profile_data.get('phone_number'),
            address=profile_data.get('address')
        )
        return user

您还可以在序列化器字段中使用

source
attr:

class UserRegistrationSerializer(serializers.ModelSerializer):
    phone_number = serializers.CharField(source='profile.phone_number', required=False, max_length=30)
    date_of_birth = serializers.DateField(source='profile.date_of_birth', required=False)
    address = serializers.CharField(source='profile.address', required=False, max_length=250)
    password = serializers.CharField(write_only=True)
    password2 = serializers.CharField(write_only=True, label='Confirm Password')

    class Meta:
        model = User
        fields = ['username', 'first_name', 'last_name', 'email', 'phone_number', 'date_of_birth', 'address', 'password', 'password2']

    def create(self, validated_data):
        profile_data = validated_data.pop('profile', {})
        password = validated_data.pop('password')
        user = User.objects.create(**validated_data)
        user.set_password(password)
        user.save()
        Profile.objects.create(
            user=user,
            phone_number=profile_data.get('phone_number'),
            date_of_birth=profile_data.get('date_of_birth'),
            address=profile_data.get('address')
        )
        return user
© www.soinside.com 2019 - 2024. All rights reserved.