我如何在Django模板中执行查询过滤

问题描述 投票:78回答:6

我需要从Django模板中执行过滤查询,以在视图中获取与python代码等效的一组对象:

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

在我想做的模板中

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

但是我似乎无法找出如何编写FILTER。

python django django-templates
6个回答
117
投票

您不能这样做,这是设计使然。 Django框架的作者打算将表示代码与数据逻辑严格分开。过滤模型是数据逻辑,而输出HTML是表示逻辑。

所以您有几种选择。最简单的方法是进行过滤,然后将结果传递到render_to_response。或者,您可以在模型中编写一个方法,以便说{% for object in data.filtered_set %}。最后,您可以编写自己的模板标记,尽管在这种情况下,我建议您不要这样做。


34
投票

我只是添加了一个额外的模板标签,如下所示:

@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 %}

11
投票

我经常遇到此问题,经常使用“添加方法”解决方案。但是,肯定存在“添加方法”或“在视图中计算”的情况不起作用(或效果不佳)的情况。例如。当您缓存模板片段并需要一些非平凡的DB计算来生成它时。除非需要,否则您不希望执行数据库工作,但是直到您深入了解模板逻辑后,您才知道是否需要这样做。

一些其他可能的解决方案:

  1. http://www.djangosnippets.org/snippets/9/处使用{%expr 作为%}模板标记”该表达式是任何合法的Python表达式,其中模板的Context作为您的本地作用域。

  2. 更改您的模板处理器。 Jinja2(http://jinja.pocoo.org/2/)的语法几乎与Django模板语言相同,但具有完整的Python功能。它也更快。您可以批发,也可以将它的使用限制为you正在使用的模板,但对设计人员维护的页面使用Django的“更安全”的模板。


9
投票

另一种选择是,如果您始终要应用过滤器,请在相关模型上添加一个custom manager,该过滤器始终将过滤器应用于返回的结果。

[这是一个很好的例子是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)

0
投票

对于任何在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

希望有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.