0

I'm using DRF. How can I get hierarchical JSON by django ORM? what the query should look like?

CategoryModel.objects.filter(active=True).select_related() or prefetch_related()?

I have model that looks like this:

    class Category(models.Model):
        parent = models.ForeignKey('self', on_delete=models.SET_NULL, blank=True, null=True)
        name = models.CharField(max_length=100)
        slug = models.SlugField(unique=True, default='', blank=True)
        active = models.BooleanField(default=True)

serializers:

class ParentCategorySerializer(serializers.ModelSerializer):

    class Meta:
        model = Category
        fields = '__all__'


class CategoryListSerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ['name', 'slug', 'parent']

    parent = ParentCategorySerializer(many=True)

I want to get something like this (greater depth possible):

{
    "name": "First category",
    "slug": "first-category",
    "subcategories": [
        {
            "name": "First subcategory one",
            "slug": "first-subcategory-one",
            "subcategories": null
        },
        {
            "name": "First subcategory two",
            "slug": "first-subcategory-two",
            "subcategories": null
        },
    ]
},
{
    "name": "Second category",
    "slug": "second-category",
    "subcategories": []
}
Виктор
  • 103
  • 2

1 Answers1

1

views.py:

from rest_framework.viewsets import ModelViewSet
from .models import Category
from .serializers import CategorySerializer


class CategoryViewSet(ModelViewSet):
    queryset = Category.objects.filter(parent=None)
    serializer_class = CategorySerializer

serialisers.py:

from rest_framework import serializers
from .models import Category
from django.db.models import CharField, Value


class CategorySerializer(serializers.ModelSerializer):
    subcategories = serializers.SerializerMethodField()

    def get_subcategories(self, obj):
        return (
            Category.objects.filter(parent_id__isnull=False, parent_id=obj.id)
            .annotate(subcategories=Value(None, output_field=CharField()))
            .values("name", "slug", "subcategories")
        )

    class Meta:
        model = Category
        fields = ["name", "slug", "subcategories"]

urls.py:

from django.urls import path
from . import views


urlpatterns = [
    path("category/", views.CategoryViewSet.as_view({"get": "list"})),
]
A D
  • 585
  • 1
  • 7
  • 16
  • how can I get more than 2 levels? (depth) – Виктор Sep 08 '22 at 08:03
  • I suggest do not reinvent the wheel, read these links [MPTT](https://django-mptt.readthedocs.io/en/latest/models.html), [1](https://stackoverflow.com/questions/41780538/how-to-create-nested-comment-system-with-django-mptt), [2](https://stackoverflow.com/questions/27073115/django-mptt-efficiently-serializing-relational-data-with-drf), [3](https://stackoverflow.com/questions/26593312/optimizing-database-queries-in-django-rest-framework/26598897#26598897). good luck :) – A D Sep 09 '22 at 07:23