Djangoでは、動的フィールド検索でQuerySetをどのようにフィルタリングしますか?


160

クラスを考える:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=20)

動的引数に基づいてフィルタリングするQuerySetを作成することは可能ですか?例えば:

 # Instead of:
 Person.objects.filter(name__startswith='B')
 # ... and:
 Person.objects.filter(name__endswith='B')

 # ... is there some way, given:
 filter_by = '{0}__{1}'.format('name', 'startswith')
 filter_value = 'B'

 # ... that you can run the equivalent of this?
 Person.objects.filter(filter_by=filter_value)
 # ... which will throw an exception, since `filter_by` is not
 # an attribute of `Person`.

回答:


310

Pythonの引数展開は、この問題を解決するために使用できます。

kwargs = {
    '{0}__{1}'.format('name', 'startswith'): 'A',
    '{0}__{1}'.format('name', 'endswith'): 'Z'
}

Person.objects.filter(**kwargs)

これは非常に一般的で便利なPythonイディオムです。


6
ちょっとした注意点:kwargsの文字列がユニコードではなくstr型であることを確認してください。そうでない場合、filter()は不平を言います。
スティーブジャリム

1
@santiagobasultoパラメータのパッキング/アンパッキング、およびそのバリエーションも指します。
Daniel Naab

7
いい、いい、いいね
オスカーメデロス2012年

5
@DanielNaabしかし、これはAND条件フィルタリング、OR条件の代替手段で機能するクワーグでのみ機能します。
Prateek099

3
@prateekあなたは常にQはオブジェクトを使用することができます:stackoverflow.com/questions/13076822/...を
deecodameeko

6

簡単な例:

Djangoサーベイアプリで、登録済みユーザーを表示するHTML選択リストが必要でした。しかし、登録ユーザー数が5000であるため、クエリ基準(特定のワークショップを完了したユーザーのみなど)に基づいてそのリストをフィルタリングする方法が必要でした。調査要素を再利用できるようにするには、調査質問を作成する人がそれらの基準をその質問に添付できるようにする必要がありました(クエリをアプリにハードコーディングしたくない)。

私が思いついた解決策は100%ユーザーフレンドリーではありません(クエリを作成するために技術者の助けが必要です)が、問題は解決します。質問を作成するとき、編集者はカスタムフィールドに辞書を入力できます。例:

{'is_staff':True,'last_name__startswith':'A',}

その文字列はデータベースに保存されます。ビューのコードでは、として戻ってきますself.question.custom_query。その値は、辞書のように見える文字列です。eval()を使用して実際の辞書に戻し、** kwargsを使用してクエリセットに入れます。

kwargs = eval(self.question.custom_query)
user_list = User.objects.filter(**kwargs).order_by("last_name")   

ユーザーがGUI側で基本的にクエリを「構築」し、実際のテキストを見ることはできないが、インターフェイスを使用して、そうする。きちんとしたプロジェクトのように聞こえます...
T. Stone

1
T.ストーン-クエリを必要とするモデルが単純であれば、そのようなツールを簡単に構築することは簡単だと思いますが、特にモデルが繁雑。
シャッカー2009

5
-1 eval()ユーザーのインポートを呼び出すことは、ユーザーを完全に信頼している場合でも、お勧めできません。ここでは、JSONフィールドの方が適しています。
ジョンカーター

5

Django.db.models.Qは、まさにDjangoの方法で必要なものです。


7
あなた(または誰か)は、動的フィールド名を使用する際にQオブジェクトを使用する方法の例を提供できますか?
jackdbernier 14

3
それはDaniel Naabの回答と同じです。唯一の違いは、引数をQオブジェクトコンストラクターに渡すことです。Q(**filters)、Qオブジェクトを動的に構築する場合は、それらをリストに入れてを使用する.filter(*q_objects)か、ビットごとの演算子を使用してQオブジェクトを結合できます。
ウィルS

5
この回答には、Qを使用してOPの問題を解決する例が含まれているはずです。
pdoherty926

-2

本当に複雑な検索フォームは、通常、より単純なモデルがそれを解決しようとしていることを示しています。

正確には、列名と操作の値をどのように取得することを期待していますか?どこの値を得るのですか?'name''startswith'

 filter_by = '%s__%s' % ('name', 'startswith')
  1. 「検索」フォーム?あなたは行くつもりです-何?-名前のリストから名前を選びますか?操作のリストから操作を選択しますか?制限のないものですが、ほとんどの人はこれがわかりにくく、使いにくいと感じています。

    そのようなフィルターはいくつの列にありますか?6?12?18?

    • いくつか?複雑な選択リストは意味がありません。いくつかのフィールドといくつかのifステートメントは意味があります。
    • たくさん?モデルが正しく聞こえません。「フィールド」は実際には列ではなく、別のテーブルの行へのキーであるように思えます。
  2. 特定のフィルターボタン。待ってください…それがDjangoの管理者のやり方です。特定のフィルターがボタンに変わります。上記と同じ分析が適用されます。いくつかのフィルターは意味があります。多数のフィルターは通常、一種の最初の正規形違反を意味します。

多くの類似したフィールドは、多くの場合、行が多くフィールドが少ないはずであることを意味します。


9
設計に関して何も知らずに推奨事項を作成することは、面倒です。このアプリケーションを「単純に実装」するには、天文学的な(> 200アプリ^ 21 foos)関数で要件を満たす必要があります。あなたは例に目的と意図を読んでいます。すべきではない。:)
ブライアン・M・ハント、

2
物事が(a)より一般的で、(b)想像どおりに機能した場合にのみ、問題を解決するのは簡単だと感じている多くの人々に出会います。物事は彼らが想像した方法ではないので、その方法は無限の欲求不満があります。「フレームワークの修正」に起因する失敗が多すぎることを確認しました。
S.Lott、2008年

2
物事はダニエルの応答に従って期待通りに機能します。私の質問は、デザインではなく構文についてでした。デザインを書き出す時間があれば、それを行っていただろう。あなたの入力は役に立つと思いますが、それは実際的な選択肢ではありません。
ブライアンM.ハント、

8
S.Lott、あなたの答えはこの質問に遠隔で答えることさえしません。答えがわからない場合は、質問をそのままにしてください。設計についてまったく知識がない場合は、一方的な設計のアドバイスを返さないでください。
slypete 2009

2
@slypete:デザインを変更して問題が解決した場合は、問題は解決しています。貧弱な設計に基づいて継続することは、必要以上に高価で複雑です。根本原因の問題を解決することは、設計上の誤った決定に起因する他の問題を解決することよりも優れています。根本原因分析が好きではありません。しかし、何かが本当に難しい場合、それは通常、最初から間違ったことを試みていることを意味します。
S.Lott、2009
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.