Как аннотировать, отфильтровать и затем получить отношения полей ForeignKey в Django (FilteredRelation или другой метод)?
Я пытаюсь аннотировать отношения ForeignKey и затем использовать новое аннотированное поле в цикле
>>> from django.db.models import FilteredRelation, Q
>>> Restaurant.objects.annotate(
... pizzas_vegetarian=FilteredRelation(
... "pizzas",
... condition=Q(pizzas__vegetarian=True),
... ),
... ).filter(pizzas_vegetarian__name__icontains="mozzarella")
Это работает. Но если я сделаю:
>>> from django.db.models import FilteredRelation, Q
>>> rests = Restaurant.objects.annotate(
... pizzas_vegetarian=FilteredRelation(
... "pizzas",
... condition=Q(pizzas__vegetarian=True),
... )
... )
... for rest in rests:
print(rest.pizzas_vegetarian)
Получаю AttributeError: «У объекта Restaurant нет атрибута „pizzas_vegetarian“»
Мне нужен доступ к этому «pizzas_vegetarian» в отдельных блоках кода. Возможно ли это с помощью FilteredRelation? Какой метод я должен использовать, чтобы получить его?
В .annotate(…)
[Django-doc] не создается атрибут на Restaurant
объектах, который используется для дальнейшей фильтрации, аннотирования и т.д. в QuerySet
.
Здесь вам нужен Prefetch
объект [Django-doc], который может заполнить отношение в отфильтрованном виде:
from django.db.models import Prefetch
Restaurant.objects.prefetch_related(
Prefetch(
'pizzas',
Pizza.objects.filter(vegitarian=True),
to_attr='pizzas_vegetarian',
)
)
Если вы точно знаете, что существует максимум одна такая вегетарианская пицца, вы также можете извлечь ее с помощью .select_related(…)
[Django-doc]:
Restaurant.objects.annotate(
pizzas_vegetarian=FilteredRelation(
'pizzas',
condition=Q(pizzas__vegetarian=True),
),
).select_related('pizzas_vegetarian')
Однако я не уверен, является ли это особенностью или по сути (непреднамеренным) побочным эффектом FilteredRelation
логики.