Django queryset içinde VEYA koşulu nasıl gerçekleştirilir?


294

Bu SQL sorgusuna eşdeğer bir Django sorgusu yazmak istiyorum:

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

Django queryset filtresi nasıl oluşturulur?

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

Bu işe yaramaz, çünkü ANDfiltrelerdir. ORBireysel sorgu kümelerinin birleşmesini sağlamak için filtreleri istiyorum .


Yanıtlar:


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

Dokümantasyon ile


Bir object.query baskısı eklerseniz yardımcı olur, böylece hem ORM hem de Query çıktısını tanımak için ilişkilendirebiliriz. BTW harika bir örnek.
Eddwin Paz

Bu tür bir sorgu kullanmak veya iki ayrı sorgu gerçekleştirmek daha mı iyidir?
MHB

60

Çünkü Sorgu kümelerini uygulamak Python __or__operatörü ( |) veya birliğe, sadece çalışır. Beklediğiniz gibi, |ikili operatör bir döner QuerySetböylece order_by(), .distinct()ve diğer QuerySet filtreleri sonuna tacked edilebilir.

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

2019-06-20 Güncellemesi: Bu artık Django 2.1 QuerySet API başvurusunda tam olarak belgelenmiştir . Daha tarihi tartışmalar DjangoProject bileti # 21333'te bulunabilir .


18
"belgesiz" ve "miras" beni korkutuyor. Burada kabul edilen cevapta ayrıntılı olarak açıklandığı gibi Q nesnesini kullanmak daha güvenli.
0man

2
FYI, order_by () ve different (), birleştirildikten sonra borulu
sorgu kümesine

@carruthd teşekkürler. Bunu da doğruladım. Düzenleyecek
Ocaklar

Order_by () her bir sorgu kümesine uygulanabilir ve sonra birleştirilebilir mi? Her koşul için düzen hala korunuyor mu? Örneğin, combined_queryset = User.objects.filter (income__gte = 5000) .order_by ('gelir') | User.objects.filter (income__lt = 5000) .order_by ('- gelir')?
çıkmaz

2
@Oatman: | operatör belgelenmiştir. Bkz. Docs.djangoproject.com/en/2.0/ref/models/querysets : "Genel olarak, Q () nesneleri koşulların tanımlanmasını ve yeniden kullanılmasını mümkün kılar. Bu, | (OR) ve & ( VE) operatörleri; özellikle, QuerySets içinde VEYA kullanmak başka türlü mümkün değildir. " Önceki sürümler için belgeleri kontrol etmedim ancak boru operatörü en azından Django 1.1.4'ten çalışıyor (sadece denedi).
makeroo

10

Her iki seçenek de mevcut cevaplarda zaten belirtilmiştir:

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

ve

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

Ancak hangisinin tercih edileceği konusunda bazı karışıklıklar var gibi görünüyor.

Mesele şu ki , SQL düzeyinde aynıdırlar , bu yüzden istediğinizi seçmekten çekinmeyin!

Django ORM Cookbook burada, bu konuda bazı ayrıntılarıyla anlatıyor ilgili parçasıdır:


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

sebep olur

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

ve

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

sebep olur

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

Kaynak: django-orm-cookbook


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.