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


82

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

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

在我的模板中,我想做

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

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

Answers:


119

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

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


2
你好人是2014年!大约6年后,JS库取得了长足的进步,应该在客户端上通过一些不错的Java脚本库(或至少是AJAX版)的支持来过滤不大量的数据。
andilabs 2014年

1
@andi:我当然同意即使是中等大小的数据集,例如表中甚至数千行。在处理了具有数百万行的数据库之后,肯定仍然有服务器端过滤的地方:)
Eli Courtwright 2014年

可以肯定,但是我只是想指出所有经常处理几千行的人,这可能会在浏览器中为用户带来很好的交互体验。对于甚至处理海量数据集的人来说,一些混合方法可能是一个很好的解决方案,例如,在服务器端过滤从几M到几K的过滤器,而在这几K内的其他较轻的人员则在客户端进行过滤。
andilabs

9
@andi,除非您根据权限过滤内容(客户端永远不会做)。对?

38

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

@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年

12

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

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

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

  2. 更改模板处理器。Jinja2(http://jinja.pocoo.org/2/)的语法几乎与Django模板语言相同,但具有完整的Python功能。它也更快。你可以这样做批发,或者你可能会限制其使用的模板,正在努力,但使用Django的“安全”的模板设计维护页面。


9

另一个选择是,如果您有一个始终要应用的过滤,则在有问题的模型上添加一个定制管理器,该定制管理器始终将过滤器应用于返回的结果。

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

3
assignment_tag已经在Django 2.0移除
安德烈亚斯BERGSTROM

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

希望能有所帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.