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 :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With