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.


Antworten:


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

über Dokumentation


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 .


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


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.