djangoテンプレートでクエリフィルタリングを実行するにはどうすればよいですか


83

ビュー内のPythonコードと同等のオブジェクトのセットを取得するには、djangoテンプレート内からフィルター処理されたクエリを実行する必要があります。

queryset = Modelclass.objects.filter(somekey=foo)

私のテンプレートでやりたい

{% for object in data.somekey_set.FILTER %}

でも、FILTERの書き方がわからないようです。

回答:


121

これは仕様によるものです。Djangoフレームワークの作成者は、プレゼンテーションコードをデータロジックから厳密に分離することを意図していました。モデルのフィルタリングはデータロジックであり、HTMLの出力はプレゼンテーションロジックです。

したがって、いくつかのオプションがあります。最も簡単なのは、フィルタリングを実行してから、結果をに渡すことrender_to_responseです。または、モデルにメソッドを記述して、と言うことができます{% for object in data.filtered_set %}。最後に、独自のテンプレートタグを作成することもできますが、この特定のケースでは、それをお勧めしません。


2
こんにちは人々は今2014年です!約6年後、JSライブラリは大きな進歩を遂げました。極端に大量ではないデータのフィルタリングは、クライアント側で、いくつかの優れたJavaScriptライブラリ、または少なくともAJAX-edをサポートして行う必要があります。
andilabs 2014年

1
@andi:適度に大きなデータセット、たとえばテーブルの数千行にも同意します。数百万行のデータベースで作業してきましたが、サーバー側のフィルタリングの場所は間違いなくあります:)
Eli Courtwright 2014年

確かに、しかし私は、多くの場合数Kの行を処理するすべての人々を指摘したかったのです。ユーザーにとって素晴らしいインタラクションの有効期限は、そのブラウザーで発生する可能性があります。そして、巨大なデータセットを扱う人々にとってさえ、いくつかのハイブリッドアプローチが良い解決策になる可能性があります。たとえば、サーバー側で数Mから数Kのフィルターを使用し、この数K内の他の軽いスタッフがクライアント側で実行します。
andilabs 2014年

9
@andiクライアント側では決して行われない権限に基づいてコンテンツをフィルタリングしている状況を除きます。正しい?

40

次のようなテンプレートタグを追加するだけです。

@register.filter
def in_category(things, category):
    return things.filter(category=category)

それから私はすることができます:

{% for category in categories %}
  {% for thing in things|in_category:category %}
    {{ thing }}
  {% endfor %}
{% endfor %}

私はこの解決策を試していますが、エラーが発生し続けます:'for' statements should use the format 'for x in y': for p in r | people_in_roll_department:d。何か案は?
diosney 2015年

@diosneyおそらく、things文に「.all」を追加します。それは「things.all」でなければなりません
エンリックMieza

12

私は定期的にこの問題に遭遇し、しばしば「メソッドの追加」ソリューションを使用します。ただし、「メソッドを追加する」または「ビューで計算する」が機能しない(またはうまく機能しない)場合は間違いなくあります。たとえば、テンプレートフラグメントをキャッシュしていて、それを生成するために重要なDB計算が必要な場合です。必要がない限りDB作業を行いたくはありませんが、テンプレートロジックを深く理解するまで、必要かどうかはわかりません。

他のいくつかの可能な解決策:

  1. http://www.djangosnippets.org/snippets/9/にある{%expr <expression> as <var_name>%}テンプレートタグを使用します。この式は、テンプレートのコンテキストをローカルスコープとする合法的なPython式です。

  2. テンプレートプロセッサを変更します。Jinja2(http://jinja.pocoo.org/2/)の構文は、Djangoテンプレート言語とほぼ同じですが、Pythonの全機能を利用できます。また、より高速です。これを大規模に行うことも、作業中のテンプレートに使用を制限することもできますが、デザイナーが管理するページにはDjangoの「より安全な」テンプレートを使用します。


9

もう1つのオプションは、常に適用するフィルターがある場合、問題のモデルにカスタムマネージャーを追加して、返される結果に常にフィルターを適用することです。

この良い例はEventモデルです。モデルに対して行うクエリの90%で、次のようなものが必要になりEvent.objects.filter(date__gte=now)ます。つまり、通常はEventsそれに関心があります。これは次のようになります。

class EventManager(models.Manager):
    def get_query_set(self):
        now = datetime.now()
        return super(EventManager,self).get_query_set().filter(date__gte=now)

そしてモデルでは:

class Event(models.Model):
    ...
    objects = EventManager()

ただし、これもEventモデルで実行されるすべてのデフォルトクエリに対して同じフィルタを適用するため、上記の手法の一部はそれほど柔軟ではありません。


9

これは、割り当てタグで解決できます。

from django import template

register = template.Library()

@register.assignment_tag
def query(qs, **kwargs):
    """ template tag which allows queryset filtering. Usage:
          {% query books author=author as mybooks %}
          {% for book in mybooks %}
            ...
          {% endfor %}
    """
    return qs.filter(**kwargs)

4
assignment_tagはDjangoの2.0で削除されました
アンドレアス・バーグストロム

1

2020年に答えを探している人のために。これは私のために働いた。

ビュー内:

 class InstancesView(generic.ListView):
        model = AlarmInstance
        context_object_name = 'settings_context'
        queryset = Group.objects.all()
        template_name = 'insta_list.html'

        @register.filter
        def filter_unknown(self, aVal):
            result = aVal.filter(is_known=False)
            return result

        @register.filter
        def filter_known(self, aVal):
            result = aVal.filter(is_known=True)
            return result

テンプレート内:

{% for instance in alarm.qar_alarm_instances|filter_unknown:alarm.qar_alarm_instances %}

擬似コードの場合:

For each in model.child_object|view_filter:filter_arg

お役に立てば幸いです。

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