Problem Statement

We will discuss how nested representation of associated objects can be handled in POST calls.

Let’s use Django polls models as reference.

The goal is to write an api which can create a question along with several choices associated with the question.

The payload would look like:

{

"pub_date": "2019-05-09T00:00",

"question_text": "Who is the most likable character in GOT?",

"choice_set": [

{

"choice_text": "Jon Snow"

},

{

"choice_text": "Arya Stark"

}

]

}

We expect a question along with two associated choices to be created.

Setup

Let’s add the following serializer:

Let’s add the following view:

Let’s verify that there are no questions or choices in the db.

In [6]: Question.objects.all()

Out[6]: <QuerySet []> In [7]: Choice.objects.all()

Out[7]: <QuerySet []>

Let’s make a POST request to create a question.

We got an AssertionError .

The error description is:

The `.create()` method does not support writable nested fields by default.

Write an explicit `.create()` method for serializer `polls.serializers.QuestionSerializer`, or set `read_only=True` on nested serializer fields.

If we make the choice_set read_only and POST without choice_set , then a question would be created.

DRF doesn’t handle creation of reverse related objects by default. We need to override serializer’s create() method to accomplish this.

Let’s create a ChoiceSerializer which will validate nested representation of a choice.

Let’s add the ChoiceSerializer as a many field on QuestionSerializer.

Let’s override create() on QuestionSerializer. QuestionSerializer would look like:

We first create the question instance. We then create the choice instances.

choice_validated_data is a list of dictionaries. Each dictionary of the list has a key called choice_text . A choice also needs to be associated with the question, that’s why we looped over the list and added question to each dictionary.

Make another api call, with choice_set in the payload.

Verify that the choices were created and they were associated with the created question.

In [13]: q = Question.objects.get() In [14]: q

Out[14]: <Question: Who is the most likable character in GOT?> In [15]: q.choice_set.all()

Out[15]: <QuerySet [<Choice: Jon Snow>, <Choice: Arya Stark>]>

I hope this was helpful to you and I want to thank you for reading this post. Hit clap in case it was helpful so that others may find it too