Django Rest Framework - User profile in nested user
I am using django rest framework to display user info. Each user has some contacts that are saved in the UserProfile (the user profile uses a one-to-one relationship to use). The contacts can be accessed directly in the custom model ( user.contacts
).
I want to show the name (and url) for all of the user's contacts. I wrote the following serializer:
class ContactsUserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ("username", "email")
class ContactsSerializer(serializers.ModelSerializer):
# user = ContactsUserSerializer(many=True) # raises TypeError: 'User' object is not iterable
class Meta:
model = UserProfile
fields = ("user",)
class UserSerializer(serializers.HyperlinkedModelSerializer):
contacts = ContactsSerializer(many=True)
class Meta:
model = get_user_model()
fields = ("url", "username", "email", "contacts")
which return
{
"url": "http:\/\/localhost:8080\/users\/1\/",
"username": "test1",
"email": "",
"contacts": [
{
"user": 2
},
{
"user": 1
}
]
}
but I want it to be:
{
"url": "http:\/\/localhost:8080\/users\/1\/",
"username": "test1",
"email": "",
"contacts": [
{
"url": "http://link_to_user",
"username": "foo"
},
{
"url": "http://link_to_user",
"username": "bar"
}
]
}
How can I achieve this? I already tried to add another serializer for contact users, but it throws an error like: the "User" object is not iterable, and the JSON structure looks a bit awkward: {contacts: [user: {"username": ...},]} which can confuse the API user if they are unsure of the Django user profile.
source to share
Yours ContactsSerializer
must be HyperlikedModelSerializer
for the field to url
be automatically added. Since you need the field url
to point to a different model, you actually need to use HyperlinkedRelatedField
and add it as a custom field in the serializer.
class ContactsSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedRelatedField(view_name="user-detail", source="user")
username = serializers.CharField(source="user.username")
class Meta:
model = UserProfile
fields = ("url", "username", )
You can use a parameter source
on a field to use a different model field than the displayed one. In this case, we use the fields from the relationship user
in the profile.
user-detail
will be the default view name if you are using a router or following the tutorial. You may need to tweak this to match your detail view.
source to share