I have my User
saved in two different models, UserProfile
and User
. Now from API perspective, nobody really cares that these two are different.
So here I have:
class UserSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = User fields = ('url', 'username', 'first_name', 'last_name', 'email')
and
class UserPSerializer(serializers.HyperlinkedModelSerializer): full_name = Field(source='full_name') class Meta: model = UserProfile fields = ('url', 'mobile', 'user','favourite_locations')
So in UserPSerializer
the field user
is just a link to that resource. But form a User perspective there is really no reason for him to know about User
at all.
Is there some tricks with which I can just mash them together and present them to the user as one model or do I have to do this manually somehow.
You can POST and PUT with @kahlo's approach if you also override the create and update methods on your serializer.
Given a profile model like this:
class Profile(models.Model): user = models.OneToOneField(User) avatar_url = models.URLField(default='', blank=True) # e.g.
Here's a user serializer that both reads and writes the additional profile field(s):
class UserSerializer(serializers.HyperlinkedModelSerializer): # A field from the user's profile: avatar_url = serializers.URLField(source='profile.avatar_url', allow_blank=True) class Meta: model = User fields = ('url', 'username', 'avatar_url') def create(self, validated_data): profile_data = validated_data.pop('profile', None) user = super(UserSerializer, self).create(validated_data) self.update_or_create_profile(user, profile_data) return user def update(self, instance, validated_data): profile_data = validated_data.pop('profile', None) self.update_or_create_profile(instance, profile_data) return super(UserSerializer, self).update(instance, validated_data) def update_or_create_profile(self, user, profile_data): # This always creates a Profile if the User is missing one; # change the logic here if that's not right for your app Profile.objects.update_or_create(user=user, defaults=profile_data)
The resulting API presents a flat user resource, as desired:
GET /users/5/ { "url": "http://localhost:9090/users/5/", "username": "test", "avatar_url": "http://example.com/avatar.jpg" }
and you can include the profile's avatar_url
field in both POST and PUT requests. (And DELETE on the user resource will also delete its Profile model, though that's just Django's normal delete cascade.)
The logic here will always create a Profile model for the User if it's missing (on any update). With users and profiles, that's probably what you want. For other relationships it may not be, and you'll need to change the update-or-create logic. (Which is why DRF doesn't automatically write through a nested relationship for you.)
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