Come eseguire la condizione OR nel django queryset?


294

Voglio scrivere una query Django equivalente a questa query SQL:

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

Come costruire il filtro Queryset Django?

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

Questo non funziona, perché sono ANDi filtri. Voglio ORi filtri per ottenere l'unione dei singoli queryset.


Risposte:


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

tramite documentazione


Sarebbe utile se aggiungi una stampa di object.query in modo da poter mettere in relazione sia l'ORM che l'output della query per familiarizzarci con esso. A proposito ottimo esempio.
Eddwin Paz,

È meglio utilizzare questo tipo di query o eseguire due query separate?
MHB,

60

Poiché i QuerySet implementano l' __or__operatore Python ( |) o unione, funziona e basta. Come ci si aspetterebbe, l' |operatore binario restituisce un QuerySetmodo order_by(), .distinct()e altri filtri QuerySet può essere appiccicato fino alla fine.

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

Aggiornamento 2019-06-20: questo è ora completamente documentato nel riferimento API QuerySet di Django 2.1 . Discussioni più storiche sono disponibili nel ticket DjangoProject n . 21333 .


18
"privi di documenti" e "eredità" mi fanno paura. Penso che sia più sicuro usare l'oggetto Q, come dettagliato nella risposta accettata qui.
0atman,

2
FYI, order_by () e distinct () possono essere applicati al
queryset con

@carruthd grazie. Ho confermato anche questo. Modifica
Piani cottura

Order_by () può essere applicato a ogni singolo queryset e quindi combinato? In modo che l'ordine per ogni condizione sia ancora mantenuto? Ad esempio, combinate_queryset = User.objects.filter (income__gte = 5000) .order_by ('income') | User.objects.filter (income__lt = 5000) .order_by ('- income')?
deadlock

2
@Oatman: | l'operatore è documentato. Vedi docs.djangoproject.com/en/2.0/ref/models/querysets : "In generale, gli oggetti Q () consentono di definire e riutilizzare le condizioni. Ciò consente la costruzione di complesse query di database utilizzando | (OR) e & ( AND) operatori; in particolare, non è altrimenti possibile utilizzare OR nei QuerySet. " Non ho controllato la documentazione per le versioni precedenti ma l'operatore di pipe funziona almeno da Django 1.1.4 (appena provato).
Makeroo,

10

Entrambe le opzioni sono già menzionate nelle risposte esistenti:

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

e

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

Tuttavia, sembra esserci una certa confusione riguardo a quale si debba preferire.

Il punto è che sono identici a livello di SQL , quindi sentiti libero di scegliere quello che preferisci!

Il libro di cucina di Django ORM parla in dettaglio, ecco la parte rilevante:


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

porta a

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%)'

e

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

porta a

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%)'

fonte: django-orm-cookbook


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.