在我的django项目中,我有两个相关的模型:
class User(AbstractUser):
email = models.EmailField(
verbose_name='e-mailaddress',
max_length=255,
unique=True)
# other props not important
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
#other props not important
对于创建和检索,将User作为序列化程序中的嵌套对象是很方便的:
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Profile
fields = '__all__'
def create(self, validated_data):
user_data = validated_data.pop('user')
user = User.objects.create(**user_data)
user.save()
# because of reasons, an empty profile is created on initial save. This works, trust me
d, _ = Profile.objects.update_or_create(user=user, defaults=validated_data)
d.save()
return d
然而。我希望能够同时更新配置文件和用户的属性。使用我的序列化程序执行此操作时,serializer.is_valid()
失败,因为提供的电子邮件已存在于数据库中。这也表明,即使验证通过(即因为更新了电子邮件地址(,也会创建一个新的用户对象并将其耦合到配置文件。所以我的问题是:
如何使序列化程序的验证检查嵌套对象的编辑是否有效,而不是检查是否可以创建新对象
您可以通过执行类似操作来更新配置文件及其相关用户的属性。
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Profile
fields = '__all__'
def update(self, instance, validated_data):
# update the profile-related fields here.
# the other properties which you didn't mention.
...
profile = instance
# get the profile object
...
instance.save()
user = validated_data.get('user')
# get the related user.
# update the user properties here, like:
user.email = 'UPDATED_EMAIL'
user.save() # you need to save the user as well as the profile!
return instance
我设法自己找到了一些变通方法。使用序列化程序字段的source
属性,可以将相关对象的某些属性添加到序列化程序中。在我的案例中,我能够为ProfileSerializer添加以下行以获得我需要的功能:
first_name = serializers.CharField(max_length=30, source='user.first_name', required=False)
last_name = serializers.CharField(max_length=150, source='user.last_name', required=False)
email = serializers.CharField(max_length=255, source='user.email')
User
还有更多的属性,但对于我目前的需求,我不需要它们,这很好(尽管如果需要所有属性,为所有属性添加这样一行会很乏味(。它确实需要create
和update
函数的自定义实现,但我认为无论如何都需要它们。我个人使用:
def create(self, validated_data):
user_data = validated_data.pop('user')
user = User.objects.create(**user_data)
user.save()
instance = ...
return instance
def update(self, instance, validated_data):
user_data = validated_data.pop('user')
user = instance.user
for k,v in user_data.items():
setattr(user, k, v)
user.save()
...
return instance
注意:django-rest自动将具有共享源对象的属性分组为嵌套对象:{'user': {'email': ..., 'first_name': ..., 'last_name': ...}, 'phone_number': ...}
(其中phone_number
是配置文件属性(