Please wait...

How to GET nested data (POST without nested) in Django REST Framework

by in Django

DRF Nested Data
In this post, you're going to learn how to get nested data from the Django REST framework.

Django REST Framework uses Serializer class that converts Django queryset to JSON with Python datatypes

But if you define Serializer class with the nested class so it will return data in nested format but it'll need the same format for POST request data.

Let me add a sample for this.

models.py

from django.db import models


class Category(models.Model):
    title = models.CharField("Title", max_length=255)


class Tag(models.Model):
    title = models.CharField("Title", max_length=255)


class Post(models.Model):
    title = models.CharField("Title", max_length=255)
    description = models.TextField()
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    tags = models.ManyToManyField(Tag)

Above we have 3 models that represent blogs models

serializer.py

from rest_framework import serializers

from .models import Category, Tag, Post


class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = "__all__"


class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = "__all__"


class PostSerializer(serializers.ModelSerializer):
    category = CategorySerializer()
    tags = TagSerializer(many=True)

    class Meta:
        model = Post
        fields = "__all__"

views.py

from rest_framework.viewsets import ModelViewSet

from .models import Post
from .serializer import PostSerializer


class PostViewSet(ModelViewSet):
    serializer_class = PostSerializer
    queryset = Post.objects.all()

As you can see in PostSerializer, it's using nested serializers CategorySerializer and TagSerializer so when we POST data through API,  data should be like:

{
  title: "How to get nested data in Django REST Framework",
  description: "Lorem Ipsum",
  category: {
    "title": "Django"
  },
  tags: [
    {
      "title": "Django"
    },
    {
      "title": "Django rest framework"
    }
  ]
}

and in this JSON Category and Tags will create and GET response will be the same from API in GET request.

Problem: Sometimes we already have categories and tags in our database so we just need to connect with the post
Solution:

We need to follow below point:

  1. Create NestedSerializerMixin 
  2. Update PostSerializer and Create a new serializer for Response only
  3. Add Attribute in view read_serializer_class

1 Create NestedSerializerMixin :

class NestedSerializerMixin(ModelViewSet):
    read_serializer_class = None

    def get_serializer_class(self):
        if self.request.method.lower() == "get":
            return self.read_serializer_class
        return self.serializer_class

2. Update PostSerializer and Create a new serializer for Response only

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = "__all__"


class NestedPostSerializer(serializers.ModelSerializer):
    category = CategorySerializer()
    tags = TagSerializer(many=True)

    class Meta:
        model = Post
        fields = "__all__"

3. Add Attribute in view read_serializer_class:


class PostViewSet(NestedSerializerMixin):
    serializer_class = PostSerializer
    queryset = Post.objects.all()
    read_serializer_class = NestedPostSerializer

Now we have changed the Serializer Class for POST and GET request.
so we can post data like:

{
  title: "How to get nested data in Django REST Framework",
  description: "Lorem Ipsum",
  category: 1,
  tags: [
    1,
    2
  ]
}

Here Category: 1 means already exist category pk, same for tags with an Array because tags have ManyToManyField

Now GET API response will show nested data

{
  title: "How to get nested data in Django REST Framework",
  description: "Lorem Ipsum",
  category: {
    "title": "Django"
  },
  tags: [
    {
      "title": "Django"
    },
    {
      "title": "Django rest framework"
    }
  ]
}

We can import NestedSerializerMixin in Django REST framework Views when we need to GET and POST different data