简体   繁体   中英

Django rest framework nested serializer partial update

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 create and update are working just fine, problem is with partial updates. The django User model has as required username and I would like to make that optional. Is there a way to enable partial updates for this scenario?

For instance I would like to update with PUT just "foo".

By default PUT is expected to supply all required arguments. But PATCH is not. So as long as you are OK with using PATCH instead of PUT you don't have to change your code at all.

Personally I think it is a little weird how that works, PUT requires all arguments that aren't optional, but will leave optional arguments alone. So you can edit optional arguments while leaving other optional arguments alone but can't do the same with required arguments (I mean you can obviously just supply the existing values, but if they changed whilst you were editing you are screwed and will force change them back). PATCH makes a lot more sense to me. Any argument you supply will be changed, and any you don't won't. IMO PUT should wipe out any optional arguments that aren't supplied, so that it is a true replace rather than simply a replace required and update (PUT) optional.

I ended up overriding get_serializer inside UsersViewSet:

    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 partial to True if request.method is PUT. Not sure if this is the most elegant solution but it works. If any one has a better solution please do share :)

Actually, the following code already supports the partial update:

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

This ' get ' function will get the 'username' field from validated_data . If it didn't exist, then instance.username would be returned.

用户序列号需要更改为类似

username = fields.CharField(required=False)

I think it is enough to enforce partial=True when you define and override the update() method in serializers.py , ie:

def update(self, instance, validated_data, partial=True):
...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM