Prenez soin de only
si vos sous-requêtes ne sélectionnent pas la clé primaire.
Exemple :
class Customer:
pass
class Order:
customer: Customer
pass
class OrderItem:
order: Order
is_recalled: bool
- Le client a des commandes
- L'ordre a des articles d'ordre
Nous essayons maintenant de trouver tous les clients ayant au moins un élément de commande rappelé.(1)
Cela ne fonctionnera pas correctement
order_ids = OrderItem.objects \
.filter(is_recalled=True) \
.only("order_id")
customer_ids = OrderItem.objects \
.filter(id__in=order_ids) \
.only('customer_id')
# BROKEN! BROKEN
customers = Customer.objects.filter(id__in=customer_ids)
Le code ci-dessus semble très bien, mais il produit la requête suivante :
select * from customer where id in (
select id -- should be customer_id
from orders
where id in (
select id -- should be order_id
from order_items
where is_recalled = true))
Au lieu de cela, il convient d'utiliser select
order_ids = OrderItem.objects \
.filter(is_recalled=True) \
.select("order_id")
customer_ids = OrderItem.objects \
.filter(id__in=order_ids) \
.select('customer_id')
customers = Customer.objects.filter(id__in=customer_ids)
(1) Note : dans un cas réel, nous pourrions envisager l'option "WHERE EXISTS".