【问题标题】:Django template {%for%} tag add li every 4th elementDjango 模板 {%for%} 标签每 4 个元素添加 li
【发布时间】:2023-10-22 22:07:01
【问题描述】:

我需要在模板中表示集合并将每四个元素包装在

<li></li>

模板应该是这样的:

<ul>
    <li>
         <a></a>
         <a></a>
         <a></a>
         <a></a>
    </li>
    <li>
         <a></a>
         <a></a>
         <a></a>
         <a></a>
    </li>
    <li>
         <a></a>
         <a></a>
         <a></a>
         <a></a>
    </li>
</ul>

所以我需要在 {% for %} 中这样做

{% for obj in objects %}
 {#add at 1th and every 4th element li wrap somehow#}
    <a>{{object}}</a>
 {# the same closing tag li#}
{% endfor %}

【问题讨论】:

    标签: django django-templates


    【解决方案1】:

    如果你想通过检查第一个 forloop 和最后一个 forloop 来工作,你可以使用这个:

    <ul>
    {% for obj in objects %}
    {% if forloop.first %}
        <li>
    {% endif %}
            <a>{{obj}}</a>
    {% if forloop.counter|divisibleby:4 and not forloop.first %}
        </li>
        <li>
    {% endif %}
    {% if forloop.last %}
        </li>
    {% endif %}
    {% endfor %}
    </ul>
    

    【讨论】:

      【解决方案2】:

      您可以使用前面提到的 divisibleby 标签,但出于清除模板的目的,我通常更喜欢返回生成器的辅助函数:

      def grouped(l, n):
          for i in xrange(0, len(l), n):
              yield l[i:i+n]
      

      示例简单视图:

      from app.helpers import grouped
      
      def foo(request):
          context['object_list'] = grouped(Bar.objects.all(), 4)
          return render_to_response('index.html', context)
      

      示例模板:

      {% for group in object_list %}
         <ul>
              {% for object in group %}
                  <li>{{ object }}</li>
              {% endfor %}
         </ul>
      {% endfor %}
      

      【讨论】:

      • 太棒了!这是迄今为止最简单、最干净、最易读的解决方案。 +1
      • 谢谢,这太棒了
      • @Hedde van der Heide 漂亮的解决方案!我建议也许用范围切换 xrange。
      【解决方案3】:

      以下应该可以解决您的问题,使用内置模板标签:

      <ul>
          <li>
          {% for obj in objects %}
              <a>{{ obj }}</a>
      
          {# if the the forloop counter is divisible by 4, close the <li> tag and open a new one #}
          {% if forloop.counter|divisibleby:4 %}
          </li>
          <li>
          {% endif %}
      
          {% endfor %}
          </li>
      </ul>
      

      【讨论】:

      • 我真的不喜欢这种在满足条件时注入结束标签的程序方式。请参阅回复*.com/a/11965885/636626 以获得更具可读性和可重用性的解决方案。
      • @NilsWerner:取决于解决方案是否适用于用例。如果 Hedde 的解决方案需要您修改大量现有代码和/或基础设施,那么与生成器对象相比,仍然采用处理平面列表的“更简单的路线”可能更可行。此外,列表按多少项分组的责任已转移给调用者。这是否是所需的方式取决于用例。话虽如此,我同意争取更清洁的模板和可重用的解决方案是可取的。
      【解决方案4】:

      我个人会考虑在将视图中的元素传递给模板之前将它们分开,然后使用嵌套的 for 循环。除此之外,您实际上只有 Vaibhav Mishra 提到的过滤器或模板标签选项。

      【讨论】:

      • 如果这 4 个对象一开始实际上并不属于一起,那么您的方法会将逻辑更紧密地与视觉表示结合起来。设计师和程序员应该能够分开工作,这毕竟是 django 的目标之一。
      • 框架,如 Django,旨在满足自己的需求,如果需要对 imo 对象进行分组,则在视图层中执行此操作非常好。当然,如果它使设计师的生活更轻松。例如。通常,排序也在模板层之外进行。
      • @Hedde 我部分同意。尽管您实际上无法将这些对象分组为固定的 4 组(例如,名称的普通列表)。设计者可能只是为了向用户提供更紧凑的数据表示。但是,如果数据必须始终分组在一起因为它们属于一起(例如,数组看起来像 [name0, surname0, address0, phone0, name1, .., nameN, ..])那么,这确实应该在视图层中完成。至少我是这样理解视图(程序员)和模板(设计师)的分离。
      【解决方案5】:

      您可以使用 divisibleby 内置过滤器,here is link to django documentation

      所以这样的事情会起作用

      {% if value|divisibleby 4 %}
      #your conditional code
      {% endif %}
      

      【讨论】: