#34791: Issue when using Prefetch objects in prefetch_related
-------------------------------------+-------------------------------------
Reporter: Maxime Toussaint | Owner: nobody
Type: Bug | Status: closed
Component: Database layer | Version: 4.2
(models, ORM) | Resolution:
Severity: Normal | worksforme
Keywords: prefetch, | Triage Stage:
prefetch_related | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Natalia Bidart):
* status: new => closed
* resolution: => worksforme
Comment:
I have created a few models of my own and tested your queries. The queries
are correct in both cases and I get expected results. I have created many
toppings and `onion` and `tomato` are out of stock:
{{{
>>> def print_toppings(q):
... print([t.name for p in q for t in p.toppings.all()], [t.name for p
in q for t in p.out_of_stock_toppings])
...
>>> q1 =
Pizza.objects.all().prefetch_related('toppings',Prefetch('toppings',
queryset=Topping.objects.filter(is_in_stock=False),
to_attr='out_of_stock_toppings'))
>>> print_toppings(q1)
['sweet pepper', 'egg', 'ham', 'bacon', 'onion', 'cheese', 'tomato',
'onion', 'sweet pepper', 'egg', 'cheese', 'onion', 'tomato'] ['onion',
'tomato', 'onion', 'onion', 'tomato']
>>> print("\n\n".join(i["sql"] for i in connection.queries))
SELECT "ticket_34791_pizza"."id", "ticket_34791_pizza"."name" FROM
"ticket_34791_pizza"
SELECT ("ticket_34791_pizza_toppings"."pizza_id") AS
"_prefetch_related_val_pizza_id", "ticket_34791_topping"."id",
"ticket_34791_topping"."name", "ticket_34791_topping"."is_in_stock" FROM
"ticket_34791_topping" INNER JOIN "ticket_34791_pizza_toppings" ON
("ticket_34791_topping"."id" = "ticket_34791_pizza_toppings"."topping_id")
WHERE "ticket_34791_pizza_toppings"."pizza_id" IN (2, 3, 4, 1)
SELECT ("ticket_34791_pizza_toppings"."pizza_id") AS
"_prefetch_related_val_pizza_id", "ticket_34791_topping"."id",
"ticket_34791_topping"."name", "ticket_34791_topping"."is_in_stock" FROM
"ticket_34791_topping" INNER JOIN "ticket_34791_pizza_toppings" ON
("ticket_34791_topping"."id" = "ticket_34791_pizza_toppings"."topping_id")
WHERE (NOT "ticket_34791_topping"."is_in_stock" AND
"ticket_34791_pizza_toppings"."pizza_id" IN (2, 3, 4, 1))
}}}
The second query also works fine:
{{{
>>> q2 = Pizza.objects.all().prefetch_related(Prefetch('toppings',
queryset=Topping.objects.filter(is_in_stock=False),
to_attr='out_of_stock_toppings'),'toppings')
>>> print_toppings(q2)
['sweet pepper', 'egg', 'ham', 'bacon', 'onion', 'cheese', 'tomato',
'onion', 'sweet pepper', 'egg', 'cheese', 'onion', 'tomato'] ['onion',
'tomato', 'onion', 'onion', 'tomato']
>>> print("\n\n".join(i["sql"] for i in connection.queries))
SELECT "ticket_34791_pizza"."id", "ticket_34791_pizza"."name" FROM
"ticket_34791_pizza"
SELECT ("ticket_34791_pizza_toppings"."pizza_id") AS
"_prefetch_related_val_pizza_id", "ticket_34791_topping"."id",
"ticket_34791_topping"."name", "ticket_34791_topping"."is_in_stock" FROM
"ticket_34791_topping" INNER JOIN "ticket_34791_pizza_toppings" ON
("ticket_34791_topping"."id" = "ticket_34791_pizza_toppings"."topping_id")
WHERE (NOT "ticket_34791_topping"."is_in_stock" AND
"ticket_34791_pizza_toppings"."pizza_id" IN (2, 3, 4, 1))
SELECT ("ticket_34791_pizza_toppings"."pizza_id") AS
"_prefetch_related_val_pizza_id", "ticket_34791_topping"."id",
"ticket_34791_topping"."name", "ticket_34791_topping"."is_in_stock" FROM
"ticket_34791_topping" INNER JOIN "ticket_34791_pizza_toppings" ON
("ticket_34791_topping"."id" = "ticket_34791_pizza_toppings"."topping_id")
WHERE "ticket_34791_pizza_toppings"."pizza_id" IN (2, 3, 4, 1)
}}}
You should note that when using `to_attr`, the result is stored in a list
as documented here (see the Note):
https://docs.djangoproject.com/en/4.2/ref/models/querysets/#prefetch-
objects
--
Ticket URL: <https://code.djangoproject.com/ticket/34791#comment:2>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/0107018a1f07d19f-0aedaf6e-9c2a-4ce2-841f-8f95e843c77d-000000%40eu-central-1.amazonses.com.