2つのDjangoクエリセットの和集合を見つけるにはどうすればよいですか?


92

2つのカスタムマネージャーメソッドを備えたDjangoモデルがあります。それぞれが、オブジェクトの異なるプロパティに基づいて、モデルのオブジェクトの異なるサブセットを返します。

各マネージャーメソッドによって返されるクエリセットの和集合であるクエリセット、またはオブジェクトのリストを取得する方法はありますか?


3
変動のために、この質問を参照してください(削除の回答から)、異なるモデルからのクエリセットを持つ作品:stackoverflow.com/questions/431628/...
rnevius

1
バージョン1.11以降、djangoクエリセットには組み込みの和集合メソッドがあります。私は将来の参考のためにそれを答えとして追加しました
Jose Cherian 2017

回答:


179

これは機能し、少しきれいに見えます:

records = query1 | query2

重複したくない場合は、以下を追加する必要があります.distinct()

records = (query1 | query2).distinct()

5
OPが要求したように、受け入れられた回答は反復可能な和集合(正確にはリスト)を返しますが、このメソッドはクエリセットの真の和集合を返します。このクエリセットはさらに操作できますが、これは多くの状況で必要です。
Krystian Cybulski 2013年

5
Djangoのバグが原因で、この構造はManyToManyFieldsを処理するときに誤った結果を返すことがあります。たとえば、それがrecords.count()より大きい場合がありますがquery1.count() + query2.count()、これは明らかに正しくありません。
Jian

4
@Jianは、バグとdjangoprojectの問題へのリンクを使用してdjangoのバージョンを明確にできますか?
IMFletcher 2013年

10
レコード= query1 | query2; records = records.distinct()で正しい結果が得られます
eugene 2013年

5
Pythonで演算子をオーバーロードできます。docs.python.org/2/library/operator.htmlを参照してください。したがって、Djangoが行うことは、QuerySetオブジェクト用の特別なメソッドを作成することです。ここでコードを参照してくださいgithub.com/django/django/blob/master/django/db/models/...QuerySetクラスのための方法を提供__and__し、__or__呼ばれたときに&、または|オペレータが2つの間で使用されQuerySet、またために使用されるオブジェクト(Qクラスならびに)。
ジョーダンライター

49

始まったバージョン1.11、Djangoのクエリセットは、組み込みの組合方法を持っています。

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

その他の例については、これに関する私のブログ投稿を参照してください。


all = Trueを機能させることができませんでした。クライアントに返す前に、クエリセットをセットにキャストすることになりました。
ブレーデンホルト

1
@ BradenHolt、all = Trueは、重複するレコードが含まれることを意味します。all = Trueを削除するだけで、セットにキャストされないようにすることができます。
JoseCherian19年

これが機能しない後、DjangoFilterBackend、unionとDjangoFilterBackendを使用するにはどうすればよいですか?
nesalexy

残念ながら、これはモデルのメタで定義されたデフォルトの順序を持​​つモデルでは機能しないようです。これらを.unionと組み合わせようとすると、「複合ステートメントのサブクエリではORDERBYは許可されていません」というエラーが表示されます。
jrial

4

'query1 |の代わりに' query1.union(query2) 'を使用することをお勧めします。query2 '; 上記の2つの方法とは異なる結果が得られましたが、前者は期待どおりでした。以下は私が出くわしたものです:

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

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

結果:

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

| result:
KafkaTopic object
KafkaTopic object

1
コードの画像ではなく、コードを貼り付けてください。画像内のテキストは検索できず、確認のためにコピーしてエディターに貼り付けることはできず、必要以上のスペースを占有します。バッククォートを使用してコードをコードとしてマークし、正しくフォーマットされるようにします。テキスト入力ボックスの横にある「ヘルプ」リンクを参照してください。
jrial

更新していただきありがとうございます。:)
jrial
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.