How to annotate, filter then get ForeignKey field relations in Django (FilteredRelation or another method)?
I'm trying to annotate ForeignKey relations and then use new annotated field in loop
>>> 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")
That works. But if i do:
>>> 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)
I get AttributeError: "Restaurant object has no attribute 'pizzas_vegetarian'"
I need access to that "pizzas_vegetarian" in separate code blocks. Is it possible with FilteredRelation? Wich method should i use to get it?
The .annotate(…)
[Django-doc] does not create an attribute on the Restaurant
objects, this is used to do further filtering, annotating, etc. in the QuerySet
.
What you need here is a Prefetch
object [Django-doc] that can populate a relation in a filtered matter:
from django.db.models import Prefetch
Restaurant.objects.prefetch_related(
Prefetch(
'pizzas',
Pizza.objects.filter(vegitarian=True),
to_attr='pizzas_vegetarian',
)
)
If you know for sure there is at most one such vegiterian pizza, you can also retrieve it with .select_related(…)
[Django-doc]:
Restaurant.objects.annotate(
pizzas_vegetarian=FilteredRelation(
'pizzas',
condition=Q(pizzas__vegetarian=True),
),
).select_related('pizzas_vegetarian')
I'm however not sure if that is a feature or essentially was an (unintended) side-effect of the FilteredRelation
logic.