39 votes

Comment faire une sous-requête dans un queryset en django ?

Comment puis-je avoir une sous-requête dans le queryset de django ? par exemple si j'ai :

select name, age from person, employee where person.id = employee.id and
employee.id in (select id from employee where employee.company = 'Private')

C'est ce que j'ai fait jusqu'à présent.

Person.objects.value('name', 'age')
Employee.objects.filter(company='Private')

mais il ne fonctionne pas car il renvoie deux résultats...

0voto

reto Points 4255

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".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X