Nested Serialization in Django REST Framework¶
In case you are serializing a model with relationships the default ModelSerializer behavior is to provide the primary key of the relationship target. In case you need to serialize the target object not just the primary key, you have (at least) two options: explicit nested serializer and implicit nested serializer using depth.
Default Relationship Serialization¶
In our e-learning example project, Course model has a relationship with Subject via the subject field.
{
"id": 6,
"title": "Django Rest Framework 101",
"slug": "drf-101",
"overview": "string",
"created": "2023-09-13T17:57:29.033182Z",
"owner": 1,
"subject": 1
}
Explicit Nested Django Rest Framework Serializer¶
We can explicitly create subject field for the CourseSerializer with a type of SubjectSerializer:
1from rest_framework import serializers
2
3from .models import Course, Subject
4from core.fields import UniqueKeyRelatedField
5
6
7class SubjectSerializer(serializers.ModelSerializer):
8 class Meta:
9 model = Subject
10 fields = "__all__"
11
12
13class CourseSerializer(serializers.ModelSerializer):
14 subject = SubjectSerializer()
15
16 class Meta:
17 model = Course
18 fields = "__all__"
Django Rest Framework will serialize the relationship using the SubjectSerializer’s output:
{
"id": 6,
"subject": {
"id": 1,
"title": "Software Development",
"slug": "soft-dev"
},
"title": "Django Rest Framework 101",
"slug": "drf-101",
"overview": "string",
"created": "2023-09-13T17:57:29.033182Z",
"owner": 1
}
Implicit Nested Django Rest Framework Serializer using depth¶
Another approcach could be to specify a positive depth attribute to the Course serializer’s Meta class:
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
depth = 1
fields = "__all__"
{
"id": 6,
"title": "Django Rest Framework 101",
"slug": "drf-101",
"overview": "string",
"created": "2023-09-13T17:57:29.033182Z",
"owner": {
"id": 1,
"password": "you-do-not-need-to-know",
"last_login": null,
"is_superuser": true,
"username": "ivang",
"first_name": "",
"last_name": "",
"email": "",
"is_staff": true,
"is_active": true,
"date_joined": "2023-09-13T17:21:09.158970Z",
"groups": [],
"user_permissions": []
},
"subject": {
"id": 1,
"title": "Software Development",
"slug": "soft-dev"
}
}
Under the hood Django Rest Framework has created a serializer for the two relationship fields in our Course model. This approach has some caveats:
The nested serializer always includs all the fileds from the relationship’s target model. You cannot exclude fields from the relationship seriaizer. One way to change this behavior is to override the .build_nested_field() method of the serializer (see here).
All relationships, which are present in the serializer are serialized using implicit nested serializer. For example, we want to provide only the owner id, not to serialize the whole object. We could achieve this by specifying PrimaryKeyRelatedField field:
courses/serializers.py¶1class CourseSerializer(serializers.ModelSerializer): 2 owner = serializers.PrimaryKeyRelatedField(queryset=Subject.objects.all()) 3 4 class Meta: 5 model = Course 6 depth = 1 7 fields = "__all__"
This would serialize the owner relationship using the primary key of the target model:
{ "id": 6, "owner": 1, "title": "Django Rest Framework 101", "slug": "drf-101", "overview": "string", "created": "2023-09-13T17:57:29.033182Z", "subject": { "id": 1, "title": "Software Development", "slug": "soft-dev" } }
Additional Information¶
For additional information you can refer to following:
Specifying nested serialization in Django Rest Framework
Nested Serializers from testdriven.io blog post provides in-depth discussion on Django Rest Framework serialization