Representing foreign key values in Django serializers

The primary purpose of a serializer is to convert a Django model or rather a database table into a format that can be transferred over the internet such as a JSON output or an XML output.

This becomes slightly tricky when you have two models that are related to each other through a foreign key or a many to many relationship. 

Serializing a model that contains a foreign key to another model can be done in various ways depending on what you plan to do with this data. Most widely used method is to use a nested serializer.

Using a nested serializer

Consider the relationship between a song and an artist. There could be multiple songs each of which may belong to the same artist thus requiring the need for a foreign key.



Let’s say that we want to present the Artist model in a way that it includes all the songs recorded by that artist. This can be achieved using a nested serializer.



Upon using the ArtistSerializer, the response that is returned will look like this



By default, a nested serializer is read only. To use this serializer for validating an input and write data into the DB, one must explicitly override the create() or update() methods as shown below:



Using default serializer relations

Writing nested serializers can usually be avoided by using the various types of serializer relations provided by the Django REST framework that you can find here

In this tutorial, we will be covering PrimaryKeyRelatedField and SlugRelatedField. The rest of the serializer relation types are pretty similar and can be used interchangeably with these depending upon your use case.

In each of these types, you can create read only serializers by setting read_only=True or you can also use these to write data by validating inputs.

If you wish to make them writable, you simply have to include a queryset parameter in the serializer along with read_only=False  which will be used to validate the inputs. 

Let’s take a look at the most commonly used serializer relation to explain this further

PrimaryKeyRelatedField

If you already have the individual objects of the related fields, you can only serialize the primary key in order to identify the objects.



This would get serialized as follows:



To make this serializer writable, use the following arguments:



SlugRelatedField

If the target of the relationship needs to be represented using a field other than the primary key, you can specify the field you would like to use.



This would get serialized as follows:



Closing notes

If you need complete control over how objects and relationships are created/represented at the time of serializing data or if you need to display the entire object at the time of serialization, using nested serializers is a better approach.

However if you are building an application where you already have access to the related models and you only need an identifier to reference them, I would recommend using one of the inbuilt serializer relations.

The above methods of handling foreign key relations in serializers are not just for ForeignKey fields. They also apply for ManyToManyField and OneToOneField.