【问题标题】:How do I perform query filtering in django templates如何在 django 模板中执行查询过滤
【发布时间】:2010-09-18 10:45:57
【问题描述】:

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

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

在我的模板中我想做

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

但我似乎不知道如何编写 FILTER。

【问题讨论】:

    标签: python django django-templates


    【解决方案1】:

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

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

    【讨论】:

    • 大家好,现在是 2014 年!大约 6 年后,JS 库取得了巨大的进步,过滤不是非常大量的数据应该在客户端完成,并支持一些不错的 java 脚本库,或者至少是 AJAX-ed。
    • @andi:我当然同意即使是中等规模的数据集,例如甚至在一个表中有数千行。处理过数百万行的数据库后,肯定还有服务器端过滤的地方:)
    • 当然,但我只是想指出所有经常处理几 K 行的人,在它的浏览器中可以为用户提供良好的交互体验。对于甚至处理大量数据集的人来说,一些混合方法可能是一个很好的解决方案,例如在服务器端过滤几 M 到几 K,而这几 K 中的其他轻量级人员在客户端执行。
    • @andi 除非您根据权限过滤内容,而这种情况永远不会在客户端完成。对吗?
    • 服务器端过滤是常见且安全的情况,而有时可以选择客户端过滤以避免对服务器的冗余调用以多次过滤相同的有限数量的记录。我不知道为什么一些 JS 库崇拜者更喜欢在客户端做很多事情。我见过一些基于 js 的仪表板,它们非常擅长快速耗尽笔记本电脑的电池
    【解决方案2】:

    我只是像这样添加一个额外的模板标签:

    @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 您可能会在 things 句子中添加“.all”。它应该是“things.all”
    【解决方案3】:

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

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

    1. 使用在http://www.djangosnippets.org/snippets/9/ 找到的 {% expr as %} 模板标记该表达式是任何合法的 Python 表达式,以模板的 Context 作为本地范围。

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

    【讨论】:

      【解决方案4】:

      另一个选项是,如果您有一个始终想要应用的过滤器,请在相关模型上添加一个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 模型上完成的所有默认查询应用相同的过滤器,因此上述一些技术并不灵活。

      【讨论】:

        【解决方案5】:

        这可以通过赋值标签来解决:

        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)
        

        编辑: assignment_tag 在 Django 2.0 中被删除,这将不再有效。

        【讨论】:

        • assignment_tag 已在 Django 2.0 中删除
        【解决方案6】:

        适合任何在 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
        

        希望对您有所帮助。

        【讨论】:

        • 虽然这可行,但将过滤器创建为函数而不是视图类上的方法被认为是更好的做法。将它们放在自己的文件中以获得更好的可维护性,而不是在视图中丢失它们。还可以进行更好的单元测试。
        猜你喜欢
        • 2020-10-03
        • 2015-03-12
        • 2023-04-11
        • 2018-09-02
        • 2010-10-15
        • 1970-01-01
        • 2013-11-27
        • 1970-01-01
        相关资源
        最近更新 更多