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.