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.