Фильтр глубоких вложенных related_set в Django

Существует две модели:

class Subject(Model):
    categories = ManyToManyField(Category, related_name='subjects')

class Category(Model):
    parent = ForeignKey('self', related_name='subcategories')

Это должно быть переведено в следующий вывод остатков:

[
    {
        ...,
        "categories": [
            {"subcategories": [{}, {} ... {}]},
            {"subcategories": [{}, {} ... {}]}
        ],
    },
    {
        ...,
        "categories": [
            {"subcategories": [{}, {} ... {}]},
            {"subcategories": [{}, {} ... {}]}
        ],
    }
]

Проблема заключается в том, чтобы иметь набор подкатегорий для каждой категории, подкатегорий, которые находятся в отношении "многие ко многим" с предметом-предком.

Пока что я думаю, что queryset должен быть примерно таким:

Subject.objects.prefetch_related(
    Prefetch(
        lookup="categories",
        queryset=Category.objects.filter(parent__isnull=True)
        .prefetch_related(
            Prefetch(
                lookup="subcategories",
                queryset=Subquery(
                    Category.objects.filter(
                        parent__pk=OuterRef("pk"),
                        subjects__id__in=OuterRef(OuterRef("pk")),
                    )
                )
            )
        )
        .distinct(),
    ),
)

Но это дает ошибку:

AttributeError: 'Subquery' object has no attribute '_chain'

Что не так с кверисетом. Как правильно поступить?

То, что вы пытаетесь сделать в одном операторе, не является ни аккуратным, ни эффективным. Лучшим подходом будет использование рекурсивной функции и последующая организация ответа. Вы можете взглянуть на следующее.

def get_sub_categories(category):
    """
    This is a function which we are using recursively to get all subcategories for a catefgory 
    """
    category_data = {'name': category.name}
    subcategories = category.subcategories.all()
    if subcategories:
       category_data['subcategories'] = [get_sub_categories(subcategory) for subcategory in subcategories]

    return category_data

Используя вышеуказанную функцию, вы можете получить желаемый ответ на заданную тему.

subject = Subject.objects.get(id=subject_id)
categories = subject.categories.all()
data = [get_sub_categories(category) for category in categories]

Ваши данные будут выглядеть следующим образом, далее вы можете внести коррективы, чтобы получить необходимые поля в соответствии с вашими потребностями

[
    {
        "name": "Government Exam",
        "subcategories": [
            {
                "name": "SSC",
                "subcategories": [
                    {
                        "name": "Physical",
                        "subcategories": [
                            {
                                "name": "Body 1"
                            },
                            {
                                "name": "Body 2"
                            }
                        ]
                    },
                    {
                        "name": "Written",
                        "subcategories": [
                            {
                                "name": "Socialogy"
                            },
                            {
                                "name": "Enviromental"
                            }
                        ]
                    }
                ]
            },
            {
                "name": "NDA"
            }
        ]
    }
]
Вернуться на верх