When creating an API using the Django REST Framework, it’s very common to have nested models. Often, we will want to serialize these nested models in a similar way to how the models are defined.

But what about the case where we have nested models of nested models? If we have to serialize a model object which is make up a list of objects, how is can this be done?

To make a very basic example, let’s say that you are trying to model imaginary cities using the Django Rest Framework.

In our imaginary cities, we have people, and with each of these people, they have different possessions.

Speaking more specifically, we have a one city to many people model, with a one person to many possesions model.

If we wanted to create these models in the Django REST Framework, we could do create the following in our models.py file:

from django.db import models

class City(models.Model):
    name = models.CharField(max_length=100)
    longitude = models.DecimalField(max_digits=16,decimal_places=8)
    latitude = models.DecimalField(max_digits=16,decimal_places=8)

class Person(models.Model):
    city = models.ForeignKey(City, related_name='city', on_delete=models.CASCADE)
    name = models.CharField(max_length=100)
    salary = models.DecimalField(max_digits=16, decimal_places=2)

class Possession(models.Model):
    person = models.ForeignKey(person, related_name='person', on_delete=models.CASCADE)
    product = models.CharField(max_length=100)
    value = models.DecimalField(max_digits=16, decimal_places=2)

We can serialize the city and person classes in the following way. Here’s our serializers.py file for the above if we want to be able to create and update these objects:

from rest_framework import serializers
from .models import City, Person, Possession

class PossessionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Possession
        fields = ('product', 'value')

class PersonSerializer(serializers.ModelSerializer):
    possessions = PossessionSerializer(many=True)

    class Meta:
        model = Person
        fields = ('name', 'salary', 'possessions')

    def create(self, validated_data):
        possessions_data = validated_data.pop('possessions')
        person = Person.objects.create(**validated_data)
        for possession_data in possessions_data:
            Possession.objects.create(person=person, **possession_data)
        return person

    def update(self, instance, validated_data):
        possessions_data = validated_data.pop('possessions')
        possessions = (instance.possessions).all()
        possessions = list(possessions)
        instance.name = validated_data.get('name', instance.name)
        instance.salary = validated_data.get('salary', instance.salary)
        instance.save()

        for possession_data in possessions_data:
            possession = possessions.pop(0)
            possession.product = possession_data.get('product', possession.product)
            possession.value = possession_data.get('value', possession.value)
            possession.save()
        return instance

class CitySerializer(serializers.ModelSerializer):
    persons = PersonSerializer(many=True)

    class Meta:
        model = City
        fields = ('name','longitude','latitude','persons')

    def create(self, validated_data):
        persons_data = validated_data.pop('persons')
        city = City.objects.create(**validated_data)
        for person_data in persons_data:
            possessions_data = model_data.pop('possessions')
            person=Person.objects.create(city=city, **persons_data)
            for possession_data in possessions_data:
                Possession.objects.create(person=person, **possession_data)
        return model_suite

    def update(self, instance, validated_data):
        persons_data = validated_data.pop('persons')
        persons = (instance.persons).all()
        persons = list(persons)
        instance.name= validated_data.get('name', instance.name)
        instance.longitude= validated_data.get('longitude', instance.longitude)
        instance.latitude= validated_data.get('latitude', instance.latitude)
        instance.save()

        for person_data in persons_data:
            person = persons.pop(0)
            variables_data = person_data.pop('possessions')
            possessions = (model.possessions).all()
            possessions = list(possessions)
            person.name = person_data.get('name', person.name)
            person.target = person_data.get('target', person.target)
            person.save()
            for possession_data in possessions_data:
                possession = possessions.pop(0)
                possession.product = possession_data.get('product', possession.product)
                possession.value = possession_data.get('value', possession.value)
                possession.save()
        return instance

Providing an update in the serializer.py file is a little bit cumbersome – but with a list of lists, you just need to do loops over each of the lists to get the appropriate values of the different variables.

In this post, I hope you have learned how to serialize a nested model of nested models – a list of lists using the Django REST Framework.

Categorized in:

Python,

Last Update: March 21, 2024