DjangoでORクエリフィルターを動的に作成する方法


104

例から、複数のORクエリフィルターを確認できます。

Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3))

たとえば、次の結果になります。

[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]

ただし、リストからこのクエリフィルターを作成します。どうやってするか?

例えば [1, 2, 3] -> Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3))


1
あなたはこれを2回尋ねたようです:stackoverflow.com/questions/852404
Dominic Rodger

この特定のユースケースでは、おそらくArticle.objects.filter(pk__in=[1, 2, 3])最新のdjangoで使用しますが、QオブジェクトをORすることでもう少し高度なことをしたい場合は、問題が依然として関連しています。
beruic

回答:


162

次のようにクエリをチェーンできます。

values = [1,2,3]

# Turn list of values into list of Q objects
queries = [Q(pk=value) for value in values]

# Take one Q object from the list
query = queries.pop()

# Or the Q object with the ones remaining in the list
for item in queries:
    query |= item

# Query the model
Article.objects.filter(query)

3
ありがとう!これは、:)は、あなたが知らなかったため、私が探していたものだった| =
ジャック・ハ・

23
次のようにしてクエリを初期化することもできます:query = Q()
chachan

5
:あなたが{:値「フィールド名」} **を使用して動的フィールドを作ることができる:= [値の値がQ({値「フィールド名が」} **)]クエリを
rechie

1
上記のようなオプションの条件を追加したい場合、Djangoで生のクエリをどのように作成できますか?
ユーザー

それは私にとってはうまくいきませんでした、理由はわかりません。クエリが結果を返さない
Mehran Nouri

83

より複雑なクエリを構築するには、組み込みQ()オブジェクトの定数Q.ORおよびQ.ANDを、次のようにadd()メソッドとともに使用するオプションもあります。

list = [1, 2, 3]
# it gets a bit more complicated if we want to dynamically build
# OR queries with dynamic/unknown db field keys, let's say with a list
# of db fields that can change like the following
# list_with_strings = ['dbfield1', 'dbfield2', 'dbfield3']

# init our q objects variable to use .add() on it
q_objects = Q(id__in=[])

# loop trough the list and create an OR condition for each item
for item in list:
    q_objects.add(Q(pk=item), Q.OR)
    # for our list_with_strings we can do the following
    # q_objects.add(Q(**{item: 1}), Q.OR)

queryset = Article.objects.filter(q_objects)

# sometimes the following is helpful for debugging (returns the SQL statement)
# print queryset.query

12
私と同じように、このスレッドの初心者にとっては、この回答をトップの回答と見なす必要があると思います。受け入れられた答えよりもDjangoesqueです。ありがとうございました!
テレサナ2015年

4
組み込みのOR演算子とAND演算子(|と&)を使用する方が、よりpythonicであると私は議論します。 q_objects |= Q(pk=item)
Bobort

パーフェクト!ありがとうございました!
RL Shyam 2017

1
listたまたま空の場合はと同等のものを返すことに注意してくださいArticle.objects.all()Article.objects.none()ただし、そのテストのために戻ることで軽減するのは簡単です。
Wil

2
あなたも初期化することができ@Wil q_objectsQ(id__in=[])。何かとORされていない限り、常に失敗し、クエリオプティマイザがうまく処理します。
ジョナサンリチャーズ

44

Pythonのreduce関数を使用してDave Webbの答えを書く短い方法:

# For Python 3 only
from functools import reduce

values = [1,2,3]

# Turn list of values into one big Q objects  
query = reduce(lambda q,value: q|Q(pk=value), values, Q())  

# Query the model  
Article.objects.filter(query)  

「組み込み」リデュースが削除され、に置き換えられたようfunctools.reduceです。 ソース
lsowen 2017年

ありがとう@lsowen、修正済み。
Tom Viner 2017年

そしてoperator.or_、ラムダの代わりに使用することが可能です。
エイジェネイン

38
from functools import reduce
from operator import or_
from django.db.models import Q

values = [1, 2, 3]
query = reduce(or_, (Q(pk=x) for x in values))

わかりましたが、どこoperatorから来たのですか?
mpiskore 2017年

1
@mpiskore:他のすべてのPythonモジュールと同じ場所:インポートします。
Ignacio Vazquez-Abrams

1
おかしい。それは本当に私の質問でした:どのモジュール/ライブラリでそれを見つけることができますか?グーグルはあまり役に立ちませんでした。
mpiskore 2017年

ああ、それはある種のDjango ORMオペレーターだと思いました。なんてばかげた、ありがとう!
mpiskore 2017年

20

おそらく、SQL INステートメントを使用する方が良いでしょう。

Article.objects.filter(id__in=[1, 2, 3])

参照してください。クエリセットAPIリファレンスを

動的ロジックでクエリを作成する必要がある場合は、次のようにすることができます(醜い+テストされていません)。

query = Q(field=1)
for cond in (2, 3):
    query = query | Q(field=cond)
Article.objects.filter(query)

1
次も使用できますquery |= Q(field=cond)
Bobort

8

ドキュメントを参照してください:

>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}

この方法は主キーのルックアップでのみ機能することに注意してください。

だからあなたが欲しいのは:

Article.objects.in_bulk([1, 2, 3])

6

プログラムでクエリするdbフィールドを設定する場合は、次のようにします。

import operator
questions = [('question__contains', 'test'), ('question__gt', 23 )]
q_list = [Q(x) for x in questions]
Poll.objects.filter(reduce(operator.or_, q_list))

6

reduceおよびor_演算子を使用して乗算フィールドでフィルタリングするソリューション。

from functools import reduce
from operator import or_
from django.db.models import Q

filters = {'field1': [1, 2], 'field2': ['value', 'other_value']}

qs = Article.objects.filter(
   reduce(or_, (Q(**{f'{k}__in': v}) for k, v in filters.items()))
)

ps fは新しいフォーマット文字列リテラルです。Python 3.6で導入されました


4

| =演算子を使用すると、Qオブジェクトを使用してクエリをプログラムで更新できます。


2
これはどこかに文書化されていますか?私は過去15分間を検索してきましたが、これが唯一の情報です。
wobbily_col

私たちの業界と同じように、それはStackOverflowに文書化されています!
クリス、

2

これは動的pkリスト用です:

pk_list = qs.values_list('pk', flat=True)  # i.e [] or [1, 2, 3]

if len(pk_list) == 0:
    Article.objects.none()

else:
    q = None
    for pk in pk_list:
        if q is None:
            q = Q(pk=pk)
        else:
            q = q | Q(pk=pk)

    Article.objects.filter(q)

q = Q()代わりにを使用してq = Noneif q is None句を削除することもできます。効率はやや劣りますが、3行のコードを削除できます。(クエリが実行されると、空のQは後でマージされます。)
Chris

1

別のオプションは、私は最近まで知らなかった- QuerySetも優先されます&|~、など、演算子を。OR Qオブジェクトはこの質問に対するより良い解決策であるという他の回答ですが、興味/議論のために、以下を行うことができます。

id_list = [1, 2, 3]
q = Article.objects.filter(pk=id_list[0])
for i in id_list[1:]:
    q |= Article.objects.filter(pk=i)

str(q.query)WHERE句内のすべてのフィルタを含む1つのクエリを返します。


1

forループ:

values = [1, 2, 3]
q = Q(pk__in=[]) # generic "always false" value
for val in values:
    q |= Q(pk=val)
Article.objects.filter(q)

削減:

from functools import reduce
from operator import or_

values = [1, 2, 3]
q_objects = [Q(pk=val) for val in values]
q = reduce(or_, q_objects, Q(pk__in=[]))
Article.objects.filter(q)

これらは両方とも同等です Article.objects.filter(pk__in=values)

valuesが空のときに必要なものを検討することが重要です。Q()開始値としての多くの答えはすべてを返しますQ(pk__in=[])より良い初期値です。これは常に失敗するQオブジェクトであり、オプティマイザーによって(複雑な方程式の場合でも)うまく処理されます。

Article.objects.filter(Q(pk__in=[]))  # doesn't hit DB
Article.objects.filter(Q(pk=None))    # hits DB and returns nothing
Article.objects.none()                # doesn't hit DB
Article.objects.filter(Q())           # returns everything

あなたがいる場合したいとき、すべてを返すようにvalues空である、あなたは、ANDとする必要があり~Q(pk__in=[])、その動作を確保するために:

values = []
q = Q()
for val in values:
    q |= Q(pk=val)
Article.objects.filter(q)                     # everything
Article.objects.filter(q | author="Tolkien")  # only Tolkien

q &= ~Q(pk__in=[])
Article.objects.filter(q)                     # everything
Article.objects.filter(q | author="Tolkien")  # everything

それQ()何もない、常に成功するQオブジェクトではないことを覚えておくことは重要です。それを含む操作は、それを完全に落とします。


0

easy ..
from django.db.models import Q import you model args =(Q(visibility = 1)|(Q(visibility = 0)&Q(user = self.user)))#Tuple parameters = {} #dic order = 'create_at'制限= 10

Models.objects.filter(*args,**parameters).order_by(order)[:limit]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.