Django prefetch_related вложенные модели

Я хочу сделать 3 lvl prefetch_related, но не могу заставить его работать.

views.py:

queryset = obj.answer.all().prefetch_related(Prefetch('question ', queryset=Question.objects.prefetch_related(Prefetch('orderedquestion', queryset=OrderedQuestion.objects.prefetch_related('select_set')))))

return AnswerSerializer(queryset, many=True).data

А в моем Serializers.py я вызываю его так:

json['name'] = answer.question.orderedquestion.select_set.get(id=i).name

Не знаю, соответствует ли это действительности, но мой класс OrderedQuestion наследует от Question.

Как я могу получить select_set в первом запросе, чтобы мой сериализатор перестал делать N запросов для каждого объекта?

Большое спасибо за помощь.

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

OfferType.objects.prefetch_related(
    Prefetch('offer_type_biurowin', queryset=OfferTypeBiurowin.objects.prefetch_related(
        Prefetch('offers', queryset=Offer.objects.select_related('locality').prefetch_related(
            Prefetch('gallery', to_attr='gallery_list')), to_attr='offer_list')
), to_attr='biurowin_list')

Отладка с помощью пакета django-debug-toolbar показывает, что этот код выполняет только 3 запроса. Эти 3 запроса необходимы, потому что так работает SQL - он содержит 3 различные таблицы, он не может получить данные из нескольких таблиц с помощью одного запроса, но это, вероятно, лучше, чем 100+ запросов без использования .prefetch_related() или .select_related().

Вы можете проверить, работает ли ваш код, используя упомянутые django-debug-toolbar или django-silk.

@EDIT: Извините, я был туп - только что заметил, что вы используете эту строку:

json['name'] = answer.question.orderedquestion.select_set.get(id=i).name

Вы не можете получить вопрос, используя прямой вызов атрибута, вы должны сделать что-то вроде этого:

answer.question_set.first().orderedquestion_set.first().select_set_set.get(id=i).name

Отношения many-to-many и reverse-fk содержат МНОЖЕСТВО объектов. Вы не можете получить только один вопрос без использования .first() или вызова первого элемента по:

answer.question_list[0]

(Если вы используете атрибут to_attr в предварительной выборке).

Также, если вы используете прямой вызов models.ForeignKey, вы должны использовать select_related(), а не prefetch_related().

Вернуться на верх