İki Django sorgu kümesinin birleşimini nasıl bulabilirim?


92

İki özel yönetici yöntemine sahip bir Django modelim var. Her biri, nesnenin farklı bir özelliğine göre modelin nesnelerinin farklı bir alt kümesini döndürür.

Bir sorgu kümesi veya yalnızca bir nesne listesi almanın bir yolu var mı, bu, her yönetici yöntemi tarafından döndürülen sorgu kümelerinin birleşimidir?


3
(Silinmiş bir yanıttan) Farklı Modellerden QuerySets ile çalışan bir varyasyon için bu soruya bakın: stackoverflow.com/questions/431628/…
rnevius

1
1.11 sürümünden başlayarak, django sorgu kümelerinde yerleşik bir birleşim yöntemi vardır. Bunu ileride başvurmak için bir cevap olarak ekledim
Jose Cherian

Yanıtlar:


179

Bu çalışıyor ve biraz daha temiz görünüyor:

records = query1 | query2

Yinelemeleri istemiyorsanız şunları eklemeniz gerekir .distinct():

records = (query1 | query2).distinct()

5
Kabul edilen yanıt, OP'nin istediği gibi yinelenebilir bir birleşim (tam liste) döndürürken, bu yöntem gerçek bir sorgu kümeleri birleşimi döndürür. Bu sorgu seti, birçok durumda arzu edilen daha fazla çalıştırılabilir.
Krystian Cybulski

5
Bir Django hatası nedeniyle, bu yapı ManyToManyFields ile uğraşırken bazen yanlış sonuçlar döndürebilir . Örneğin, bazen records.count()bunun daha büyük olacağını göreceksiniz ki bu query1.count() + query2.count()açıkça yanlıştır.
Jian

4
@Jian, django versiyonunu bug ve djangoproject konusuna bir bağlantı ile açıklayabilir misiniz?
IMFletcher

10
kayıtlar = sorgu1 | sorgu2; kayıtlar = kayıtlar.distinct () bana doğru sonucu verir
eugene

5
Python'da operatörleri aşırı yükleyebilirsiniz. Docs.python.org/2/library/operator.html adresine bakın . Yani Django'nun yaptığı, QuerySet nesnesi için özel yöntemler oluşturmaktır. Burada kod bakınız: github.com/django/django/blob/master/django/db/models/...QuerySet sınıfı için yöntemler sağlar __and__ve __or__adı zaman bu &veya |operatörler iki arasında kullanılır QuerySet, aynı zamanda kullanılan nesneler ( Qbir sınıf olarak da ).
Jordan Reiter

49

1.11 sürümünden başlayarak , django sorgu kümelerinin yerleşik bir birleşim yöntemi vardır.

q = q1.union(q2) #q will contain all unique records of q1 + q2
q = q1.union(q2, all=True) #q will contain all records of q1 + q2 including duplicates
q = q1.union(q2,q3) # more than 2 queryset union

Daha fazla örnek için bu konudaki blog yazıma bakın .


Hepsini alamadım = Çalışmak için Doğru. İstemciye döndürmeden önce sorgu kümemi bir kümeye yayınlamayı bıraktım.
Braden Holt

1
@BradenHolt, all = True, yinelenen kayıtlar içereceği anlamına gelir. Bir kümeye dönüştürmekten kaçınmak için tümünü = True kaldırabilirsiniz.
Jose Cherian

bundan sonra DjangoFilterBackend çalışmaz, union ve DjangoFilterBackend'i nasıl kullanabilirim?
nesalexy

Ne yazık ki, bu, modelin Meta'sında tanımlanan varsayılan bir sıralamaya sahip modeller için işe yaramıyor gibi görünüyor. Bunları .union ile birleştirmeye çalıştığımda, şu hatayı alıyorum: "SİPARİŞ TARAFINDAN bileşik ifadelerin alt sorgularında izin verilmiyor."
2019

4

'Sorgu1 | yerine' sorgu1.union (sorgu2) 'kullanmanızı öneririm. sorgu2 '; Yukarıdaki iki yöntemden farklı sonuçlar aldım ve birincisi beklediğim gibi. Aşağıdakiler karşılaştığım şey:

print "union result:"
for element in query_set1.union(query_set2):
    print element

print "| result:"
for element in (query_set1 | query_set2):
    print element

sonuç:

union result:
KafkaTopic object
KafkaTopic object
KafkaTopic object
KafkaTopic object
KafkaTopic object

| result:
KafkaTopic object
KafkaTopic object

1
Lütfen kod resimlerini değil, kodu yapıştırın. Resimlerdeki metin aranamaz, doğrulama için düzenleyicinize kopyalayıp / yapıştıramazsınız ve gerekenden daha fazla yer kaplar. Kodu kod olarak işaretlemek için ters işaretleri kullanın, böylece doğru biçimlendirilir. Metin giriş kutusunun yanındaki "yardım" bağlantısına bakın.
2019

Güncellediğiniz için teşekkürler. :)
jrial
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.