Вложенные запросы через связанные поля в django.db
1,00
р.
р.
В проекте имеются модели Семья (Family), Категория (Category) и Подкатегория (Subcategory): class Family(models.Model): name = models.CharField(max_length=100) class Category(models.Model): name = models.CharField(max_length=100) class Trend(models.Model): name = models.CharField(max_length=100) area = models.ForeignKey(Area, related_name='subcategories') families = models.ManyToManyField(Family, related_name='subcategories') Таким образом структура БД выглядит так:
Получается, что во всей системе есть единые категория и подкатегории. При этом семьи могут для себя отключать подкатегории (если есть связь между Family и Subcategory, то значит подкатегория для семьи активна). Пытаюсь вывести все категории и подкатегории, добавив к подкатегориям дополнительный параметр active. На чистом sql запрос выглядит следующим образом: SELECT cat.*, subcat.*, CASE WHEN tr.id IN ( SELECT tr.id FROM family fam INNER JOIN subcategoryfamilyrel rel ON fam.id = rel.family_id INNER JOIN subcategory subcat1 ON rel.trend_id = subcat1.id WHERE fam.id = {family.id} ) THEN 1 ELSE 0 END AS active FROM subcategory subcat INNER JOIN category cat ON subcat.category_id = cat.id Но при этом не могу понять, как правильно составить запрос через ORM. Дошел пока до того, что генерирую queryset, где классом модели выступает Category: Subcategory.objects.annotate( active=Case( When(id__in=profile.family.subcategories.all().values('id'), then=True), default=Value(False), output_field=BooleanField() ) ) И при передаче queryset в rest_framework.Serializer на выходе получается следующее: [ { "id": 1, "name": "Русский язык", "active": true, "area": { "id": 1, "name": "Школа", "color": "123456" } }, { "id": 2, "name": "Математика", "active": , "area": { "id": 1, "name": "Школа", "color": "123456" } }, { "id": 6, "name": "Уборка", "active": true, "area": { "id": 2, "name": "Дом", "color": "ABCDEF" } } ] А хотелось бы получать такое: [ { "id": 1, "name": "Школа", "color": "123456", "subcategories": [ { "id": 1, "name": "Русский язык", "active": true }, { "id": 2, "name": "Математика", "active": false } ] }, { "id": 2, "name": "Дом", "color": "ABCDEF", "subcategories": [ { "id": 3, "name": "Уборка", "active": true } ] } ] Пока я вижу два решения: Создавать запрос, отталкиваясь от Category, при этом в связанную Subcategory добавить поле active Существующий запрос с подкатегориями объединить под общими категориями.
Ответ models.py from django.db import models class Category(models.Model): name = models.CharField(max_length=100) parent_category = models.ForeignKey( to='Category', related_name='subcategories', blank=True, null=True, on_delete=models.CASCADE) serializers.py from rest_framework import serializers from .models import Category class SubCategorySerializer(serializers.ModelSerializer): class Meta: model=Category fields=('id', 'name') class RootCategorySerializer(serializers.ModelSerializer): subcategories = serializers.SerializerMethodField('get_subcategories') class Meta: model=Category fields=('id', 'name', 'subcategories') def get_subcategories(self, obj): qs = obj.subcategories.all() return SubCategorySerializer(qs, many=True)
views.py from rest_framework import generics class CategoryView(generics.ListAPIView): serializer_class = RootCategorySerializer queryset = Category.objects.filter(parent_category=None) Если ничего не забыл, и правильно понял запрос, то как-то так должно работать.