我正在 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
并且不会给我错误那些。任何输入都会有帮助。谢谢!
这是我的代码。
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}'
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
class UserRegistrationView(generics.CreateAPIView):
serializer_class = UserRegistrationSerializer
queryset = User.objects.all()
出现此错误的原因是没有属于用户的电话号码、出生日期和地址,因此 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