3

I'm using django's rest framework to show information about the user. Every user has some contacts that are saved in UserProfile (user profile uses a one-to-one relationship to use). The contacts can be accessed directly in the user model (user.contacts).
I want to display the name (and URL) for all contacts of a user. 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 that? I already tried to add another serializer for the contact users but that raises a Type Error: 'User' object is not iterable and the JSON structure would look a little bit awkward: {contacts: [ user: {"username": ...},]}, which might confuse the user of the API if he isn't confident with Django's User Profile.

1 Answer 1

7

Your ContactsSerializer would need to be a HyperlikedModelSerializer in order for the url field to be automatically added. Since you need the url field to point to a different model, you would actually need to use a HyperlinkedRelatedField and add it as a custom field on 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 the source parameter to a field to use a different field on the model than what is being displayed. In this case, we are using fields from the user relationship on the profile.

user-detail would be the default view name if you were using a router or followed the tutorial. You may need to adjust this to match your detail view name.

Sign up to request clarification or add additional context in comments.

1 Comment

Works perfectly, but it should be HyperlinkedRelatedField (or HyperlinkedIdentityField) instead of HyperlinkedModelSerializer!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.