Comment effectuer la condition OR dans le jeu de requêtes Django?


294

Je veux écrire une requête Django équivalente à cette requête SQL:

SELECT * from user where income >= 5000 or income is NULL.

Comment construire le filtre de jeu de requêtes Django?

User.objects.filter(income__gte=5000, income=0)

Cela ne fonctionne pas, car ce ANDsont les filtres. Je veux que ORles filtres obtiennent l'union des ensembles de requêtes individuels.


Réponses:


548
from django.db.models import Q
User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True))

via la documentation


Il serait utile que vous ajoutiez une impression de object.query afin que nous puissions relier à la fois la sortie ORM et Query pour la familiariser. BTW excellent exemple.
Eddwin Paz

Est-il préférable d'utiliser ce type de requête ou d'effectuer deux requêtes distinctes?
MHB

60

Parce que QuerySets implémente l' __or__opérateur Python ( |), ou union, cela fonctionne simplement. Comme on pouvait s'y attendre, l' |opérateur binaire renvoie QuerySetdonc order_by(), .distinct()et d' autres filtres QuerySet peut être clouée à la fin.

combined_queryset = User.objects.filter(income__gte=5000) | User.objects.filter(income__isnull=True)
ordered_queryset = combined_queryset.order_by('-income')

Mise à jour 2019-06-20: Ceci est maintenant entièrement documenté dans la référence de l'API QuerySet Django 2.1 . Une discussion plus historique peut être trouvée dans le ticket DjangoProject # 21333 .


18
«sans papiers» et «héritage» me font peur. Je pense qu'il est plus sûr d'utiliser l'objet Q, comme détaillé dans la réponse acceptée ici.
0atman le

2
FYI, order_by () et distinct () peuvent être appliqués au jeu de requêtes canalisé après leur combinaison
carruthd

@carruthd merci. Je l'ai également confirmé. Éditera
plaques de cuisson

L'ordonnance_by () peut-elle être appliquée à chaque ensemble de requêtes individuel puis combinée? Pour que l'ordre de chaque condition soit toujours maintenu? Par exemple, combine_queryset = User.objects.filter (revenue__gte = 5000) .order_by ('revenue') | User.objects.filter (revenue__lt = 5000) .order_by ('- revenue')?
impasse

2
@Oatman: | l'opérateur est documenté. Voir docs.djangoproject.com/en/2.0/ref/models/querysets : "En général, les objets Q () permettent de définir et de réutiliser les conditions. Cela permet la construction de requêtes de base de données complexes en utilisant | (OR) et & ( AND); en particulier, il n'est pas possible d'utiliser OR dans QuerySets. " Je n'ai pas vérifié la documentation des versions antérieures mais l'opérateur de pipe fonctionne au moins à partir de Django 1.1.4 (juste essayé).
makeroo

10

Les deux options sont déjà mentionnées dans les réponses existantes:

from django.db.models import Q
q1 = User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True))

et

q2 = User.objects.filter(income__gte=5000) | User.objects.filter(income__isnull=True)

Cependant, il semble y avoir une certaine confusion quant à la préférence.

Le fait est qu'ils sont identiques au niveau SQL , alors n'hésitez pas à choisir celui que vous aimez!

Le livre de recettes Django ORM en parle en détail, voici la partie pertinente:


queryset = User.objects.filter(
        first_name__startswith='R'
    ) | User.objects.filter(
    last_name__startswith='D'
)

mène à

In [5]: str(queryset.query)
Out[5]: 'SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login",
"auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name",
"auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff",
"auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user"
WHERE ("auth_user"."first_name"::text LIKE R% OR "auth_user"."last_name"::text LIKE D%)'

et

qs = User.objects.filter(Q(first_name__startswith='R') | Q(last_name__startswith='D'))

mène à

In [9]: str(qs.query)
Out[9]: 'SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login",
 "auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name",
  "auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff",
  "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user"
  WHERE ("auth_user"."first_name"::text LIKE R% OR "auth_user"."last_name"::text LIKE D%)'

source: django-orm-cookbook


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.