Wie führe ich eine OP-Bedingung in einem Django-Abfrageset durch?

294

Ich möchte eine Django-Abfrage schreiben, die dieser SQL-Abfrage entspricht:

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

Wie konstruiere ich den Django-Queryset-Filter?

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

Dies funktioniert nicht, weil es ANDdie Filter sind. Ich möchte, dass ORdie Filter die Vereinigung einzelner Abfragesätze erhalten.

Elisa
quelle

Antworten:

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

über Dokumentation

Lakshman Prasad
quelle
Es wäre hilfreich, wenn Sie einen Ausdruck von object.query hinzufügen, damit wir sowohl die ORM- als auch die Query-Ausgabe in Beziehung setzen können, um uns damit vertraut zu machen. Übrigens ein gutes Beispiel.
Eddwin Paz
Ist es besser, diese Art von Abfrage zu verwenden oder zwei separate Abfragen durchzuführen?
MHB
60

Da QuerySets den Python- __or__Operator ( |) oder die Union implementieren , funktioniert dies einfach. Wie zu erwarten, gibt der |Binäroperator ein QuerySetso zurück order_by(), .distinct()und andere Abfragesatzfilter können bis zum Ende angeheftet werden.

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

Update 2019-06-20: Dies ist jetzt vollständig in der QuerySet-API-Referenz für Django 2.1 dokumentiert . Weitere historische Diskussionen finden Sie im DjangoProject-Ticket Nr. 21333 .

Kochfelder
quelle
18
"undokumentiert" und "Vermächtnis" machen mir Angst. Ich denke, es ist sicherer, das Q-Objekt zu verwenden, wie in der akzeptierten Antwort hier beschrieben.
0atman
2
FYI, order_by () und different () können nach dem Kombinieren auf das Piped-Queryset angewendet werden
Carruthd
@ Carruthd danke. Das habe ich auch bestätigt. Wird bearbeiten
Kochfelder
Kann order_by () auf jeden einzelnen Abfragesatz angewendet und dann kombiniert werden? Damit die Reihenfolge für jede Bedingung noch eingehalten wird? Beispiel: kombiniertes_queryset = User.objects.filter (Einkommen__gte = 5000) .order_by ('Einkommen') | User.objects.filter (Einkommen__lt = 5000) .order_by ('- Einkommen')?
Deadlock
2
@Oatman: | Bediener ist dokumentiert. Siehe docs.djangoproject.com/de/2.0/ref/models/querysets : "Im Allgemeinen ermöglichen Q () - Objekte das Definieren und Wiederverwenden von Bedingungen. Dies ermöglicht die Erstellung komplexer Datenbankabfragen mit | (OR) und & ( AND) -Operatoren, insbesondere ist es nicht möglich, OR in QuerySets zu verwenden. " Ich habe die Dokumentation für frühere Versionen nicht überprüft, aber der Pipe Operator funktioniert mindestens ab Django 1.1.4 (nur ausprobiert).
Makeroo
10

Beide Optionen sind bereits in den vorhandenen Antworten erwähnt:

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

und

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

Es scheint jedoch einige Verwirrung darüber zu geben, welche man bevorzugen soll.

Der Punkt ist, dass sie auf SQL-Ebene identisch sind. Wählen Sie also aus, was Sie möchten!

Das Django ORM-Kochbuch spricht ausführlich darüber, hier ist der relevante Teil:


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

führt zu

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

und

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

führt zu

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

Quelle: Django-Orm-Kochbuch


Jojo
quelle