Django sorgusundaki OR filtresini nasıl yapabilirim?


303

Bir kullanıcının eklediği (içerik oluşturucu olarak listelenenler) veya öğenin onaylandığı öğeleri listeleyebilmek istiyorum.

Bu yüzden temelde seçmem gerekiyor:

item.creator = owner or item.moderated = False

Bunu Django'da nasıl yapabilirim? (tercihen bir filtre veya queryset ile).

Yanıtlar:


544

Orada Qkarmaşık aramalar için izin nesneler. Misal:

from django.db.models import Q

Item.objects.filter(Q(creator=owner) | Q(moderated=False))

6
bu programlı olarak nasıl yapılabilir? Yani, örneğinfor f in filters: Item.objects.filter(Q(creator=f1) | Q(creator=f2) | ...)
Alexis

14
@AlexisK reduce(lambda q, f: q | Q(creator=f), filters, Q())Büyük Q nesnesini oluşturmak için benzer bir şey kullanın .
Phob

24
@alexis: Item.objects.filter(creator__in=creators)örneğin bunu da yapabilirsiniz .
Kevin London

4
|VEYA operatörü olarak kullanılmanın nereden geldiğini merak ediyorsanız (benim gibi) , bu aslında set birliği operatörüdür. Ayrıca bitwise olarak (burada değil) VEYA kullanılır: stackoverflow.com/questions/5988665/pipe-character-in-python
e100

124

| Qu nesnelerini Q nesnelerine ihtiyaç duymadan doğrudan birleştirmek için operatör:

result = Item.objects.filter(item.creator = owner) | Item.objects.filter(item.moderated = False)

(değiştir - Başlangıçta bu ekstra bir sorguya neden olduysa emin değildim ama @spookylukey tembel queryset değerlendirmesinin bununla ilgilendiğine dikkat çekti)


4
Belirli bir istekte hangi sorguların yürütüldüğünü bulmak için, hata ayıklama araç çubuğu Django uygulamasını kullanabilirsiniz. Müthiş ve kazanmış.
Deniz Doğan

25
'django.db içe aktarma bağlantısından' yapın ve 'connection.queries' kullanın. Bunun için DEBUG = True gerekir. BTW, QuerySets tembel olduğunu bilmeli ve bu DB sadece bir kez vurur.
spookylukey

1
Hariç tutulan karşılaştırmalar ile hariç tutulabilir mi?
Neob91

2
bu sonuç sorgu kümesinde yinelenmelerle sonuçlanabilir mi?
Charles Haro

1
Daha spesifik olarak, sorgu kümeleri DB'yi yalnızca bunlara endekslemeye çalıştığınızda vurma eğilimindedir, aksi takdirde sadece bir sorgu oluşturursunuz.
awiebe

41

Q ifadeleri eklemenin mümkün olduğunu belirtmek gerekir .

Örneğin:

from django.db.models import Q

query = Q(first_name='mark')
query.add(Q(email='mark@test.com'), Q.OR)
query.add(Q(last_name='doe'), Q.AND)

queryset = User.objects.filter(query)

Bu, aşağıdaki gibi bir sorgu ile sonuçlanır:

(first_name = 'mark' or email = 'mark@test.com') and last_name = 'doe'

Bu şekilde uğraşmanıza veya operatörlere, azaltmaya vb.


2
Ama yazmak daha kolay query |= Q(email='mark@test.com')mı?
Alex78191

26

Filtreyi dinamik yapmak istiyorsunuz, o zaman Lambda'yı

from django.db.models import Q

brands = ['ABC','DEF' , 'GHI']

queryset = Product.objects.filter(reduce(lambda x, y: x | y, [Q(brand=item) for item in brands]))

reduce(lambda x, y: x | y, [Q(brand=item) for item in brands]) eşittir

Q(brand=brands[0]) | Q(brand=brands[1]) | Q(brand=brands[2]) | .....

6
Benim için mükemmel cevap! Python3 için from functools import reduceönceden yapın.
Dharmit

1
Neden operator.or_yerine kullanmıyorsunuz lambda x, y: x | y?
Alex78191

20

Eski answerera'ya benzer, ancak lambda olmadan biraz daha basit:

filter_kwargs = {
    'field_a': 123,
    'field_b__in': (3, 4, 5, ),
}

Bu iki koşulu aşağıdakileri kullanarak filtrelemek için OR:

Item.objects.filter(Q(field_a=123) | Q(field_b__in=(3, 4, 5, ))

Aynı sonucu programlı olarak almak için:

list_of_Q = [Q(**{key: val}) for key, val in filter_kwargs.items()]
Item.objects.filter(reduce(operator.or_, list_of_Q))

(netlik için burada iki satır halinde kesilmiştir)

operatorstandart kütüphanede: import operator
docstring'den:

or_ (a, b) - a ile aynı | b.

Python3 için, reduceartık bir yerleşik değildir , ancak hala standart kütüphanede bulunmaktadır:from functools import reduce


PS

list_of_QBoş olmadığından emin olmayı unutmayın - reduce()boş listede boğulur, en az bir elemana ihtiyacı vardır.


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.