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.