ModelSerializer vs HyperlinkedModelSerializer

  • ModelSerializer
    • By default, Relationship will show –> as primary keys
  • HyperlinkedModelSerializer
    • By default, Relationship will show –> as url
# This (ModelSerializer)
{
    "id": 3,
    "question": "What is MF",
    "author": 2
},

# Turns to this (HyperlinkedModelSerializer)
{
    "url": "http://127.0.0.1:8000/api/questions/3/",
    "question": "What is MF",
    "author": "http://127.0.0.1:8000/users/2/"
},

Doc: https://www.django-rest-framework.org/api-guide/relations/

Doc: https://www.django-rest-framework.org/api-guide/serializers/#hyperlinkedmodelserializer

View CODE here: https://github.com/amrit94/drf-test/blob/08-Relationship-and-Hyperlink/snippets/serializers.py

7.1 ReadOnlyField

  • This will be readonly-field, can’t edit
  • GET will display owner-field, But POST will not accept owner-field
# serializer.py
owner = serializers.ReadOnlyField(source='owner.username')

# If above line not used --> primary-key will be displayed
{"owner": 1}  --> { "owner": "dev"} 

The source argument controls which attribute is used to populate a field, and can point at any attribute on the serialized instance.

It can also take the dotted notation shown above, in which case it will traverse the given attributes, in a similar way as it is used with Django’s template language

7.2 PrimaryKeyRelatedField

  • Used in reverse relationship
  • related_name in Model in needed

Because ‘snippets’ is a reverse relationship on the User model, it will not be included by default when using the ModelSerializer class, so we needed to add an explicit field for it.

  • Related field primary-key is displayed
# serializer.py
snippet_owner = serializers.PrimaryKeyRelatedField(many=True, 
      queryset=Snippet.objects.all())
# OR
snippet_owner = serializers.PrimaryKeyRelatedField(many=True,
      read_only=True)
  • NOTE:
    • snippet_owner --> related_name
# API - OUTPUT
[{
    "id": 1,
    "username": "localadmin",
    "snippet_owner": [
        2,
        3
    ]
},]

Arguments:

queryset - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set read_only=True.

many - If applied to a to-many relationship, you should set this argument to True.

allow_null - If set to True, the field will accept values of None or the empty string for nullable relationships. Defaults to False.

pk_field - Set to a field to control serialization/deserialization of the primary key’s value. For example, pk_field=UUIDField(format=‘hex’) would serialize a UUID primary key into its compact hex representation.

7.3 StringRelatedField

  • Used in reverse relationship
  • related_name in Model in needed
  • Displays data returned by __str__() in models – instead of primary-key
  • NOTE
    • Model ‘related-name’ is mandatory
snippet_owner = serializers.StringRelatedField(many=True)

# person = serializers.StringRelatedField()  # O2O
# person_post = serializers.StringRelatedField(many=True)  # M2O
# publications = serializers.StringRelatedField(many=True) # M2M
# http://127.0.0.1:8000/users/
[{
  "id": 1,
  "username": "localadmin",
  "snippet_owner": [
      "2: L2",
      "3: L2"
  ]
},]

Arguments

many - If applied to a to-many relationship, you should set this argument to True.

7.4 SlugRelatedField

  • Used in reverse relationship
  • related_name in Model in needed
  • Can display any field of the related model
snippet_owner = serializers.SlugRelatedField(many=True, 
      read_only=True, slug_field='language')
[{
    "id": 1,
    "username": "localadmin",
    "snippet_owner": [
        "js",
        "java"
    ]
},]

Arguments

slug_field - The field on the target that should be used to represent it. This should be a field that uniquely identifies any given instance. required

queryset - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set read_only=True.

many - If applied to a to-many relationship, you should set this argument to True.

allow_null - If set to True, the field will accept values of None or the empty string for nullable relationships. Defaults to False.

7.5 HyperlinkedRelatedField

  • Used in reverse relationship
  • related_name in Model in needed

HyperlinkedRelatedField may be used to represent the target of the relationship using a hyperlink.

snippet_owner = serializers.HyperlinkedRelatedField(many=True, 
      view_name='snippet-detail', read_only=True)
[{
    "id": 1,
    "username": "localadmin",
    "snippet_owner": [
        "http://127.0.0.1:8000/snippets/2/",
        "http://127.0.0.1:8000/snippets/3/"
    ]
},]

Arguments:

view_name - The view_name is the name of url-pattern. If you’re using the standard router classes this will be a string with the format <modelname>-detail. required

queryset - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set read_only=True.

many - If applied to a to-many relationship, you should set this argument to True.

allow_null - If set to True, the field will accept values of None or the empty string for nullable relationships. Defaults to False.

lookup_field - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is ‘pk’.

lookup_url_kwarg - The name of the keyword argument defined in the URL conf that corresponds to the lookup field. Defaults to using the same value as lookup_field.

format - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the format argument.

7.6 HyperlinkedIdentityField

  • Used in HyperlinkedModelSerializer
    • many=True is removed
    • Only first value will be shown
snippet_owner = serializers.HyperlinkedIdentityField(
      view_name='snippet-detail', read_only=True)
[{
    "id": 1,
    "username": "localadmin",
    "snippet_owner": "http://127.0.0.1:8000/snippets/1/"
},]

Arguments

view_name - The view name that should be used as the target of the relationship. If you’re using the standard router classes this will be a string with the format <model_name>-detail. required.

lookup_field - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is ‘pk’.

lookup_url_kwarg - The name of the keyword argument defined in the URL conf that corresponds to the lookup field. Defaults to using the same value as lookup_field.

format - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the format argument.

  • M2O, M2M
    • If rel_name not defined –> source required
      • source=<model_name>_set is used
class PersonSerializer(serializers.ModelSerializer):
    # If rel_name not defined
    person_post = PostsSerializer(source='posts_set', many=True)
    # If rel_name is defined
    # person_post = PostsSerializer(many=True)

Reference