Partial update of nested Django serializer

Serializer:

class ProfileSerializer(serializers.ModelSerializer): class Meta: model = UserProfile fields = ('foo', 'bar') class UserSerializer(serializers.ModelSerializer): userprofile = ProfileSerializer(partial=True) class Meta: model = User fields = ('username', 'password', 'email', 'userprofile') def create(self, validated_data): profile_data = validated_data.pop('userprofile') user = User.objects.create(**validated_data) UserProfile.objects.create(user=user, **profile_data) return user def update(self, instance, validated_data): profile_data = validated_data.pop('userprofile') profile = instance.userprofile instance.username = validated_data.get('username', instance.username) instance.email = validated_data.get('email', instance.email) instance.save() profile.foo = profile_data.get('foo', profile.foo) profile.bar = profile_data.get('bar', profile.bar) profile.save() return instance 

View:

 class UsersViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer authentication_classes = (TokenAuthentication,) permission_classes = (IsAuthenticated,) 

Both creations and updates work very well, the problem is with partial updates. The django user model has the required username, and I would like to make this optional. Is there a way to enable partial updates for this scenario?

For example, I would like to update with the help of PUT only "foo".

+5
source share
4 answers

By default, PUT is expected to provide all the necessary arguments. But the WAY is not. So while you're fine using PATCH instead of PUT, you don’t need to change your code at all.

Personally, I think it’s a little strange how this works, PUT requires all arguments that are not optional, but will leave the optional arguments alone. This way you can edit the optional arguments, leaving the other optional arguments, but you cannot do the same with the required arguments (I mean, you can obviously just provide the existing values, but if they have changed while you are editing, you are screwed and make them change back). PATCH makes a lot more sense to me. Any argument you put will be changed, and any of you will not. IMO PUT must destroy any optional arguments that are not supplied, so this is more of a substitute, not just a required replacement and update (PUT).

+5
source

I ended up overriding get_serializer inside UserViewSet:

  def get_serializer(self, instance=None, data=None, many=False, partial=False): """If request is not PUT, allow partial updates.""" if self.request.method == 'PUT': return UserSerializer(instance=instance, data=data, many=many, partial=True) else: return UserSerializer(instance=instance, data=data, many=many, partial=partial) 

Forcing a partial to True if request.method is PUT. Not sure if this is the most elegant solution, but it works. If anyone has a better solution, share :)

+4
source

Actually, the following code already supports partial updating:

 instance.username = validated_data.get('username', instance.username) 

This get function will get the 'username field from validated_data strong>. If it does not exist, the instance name will be returned.

+1
source

Seriliazer user should change to something like

 username = fields.CharField(required=False) 
+1
source

Source: https://habr.com/ru/post/1209478/


All Articles