【问题标题】:Django template counter in nested loops嵌套循环中的 Django 模板计数器
【发布时间】:2012-12-01 23:52:27
【问题描述】:

您好,我有一个要传递给 Django 模板的两个字典的列表:

base_parts = [
    {'important item': 43},
    {'lesser item': 22, 'lesser item': 3, 'lesser item': 45}
]

在我的模板中我可以这样做:

{% for base_part in base_parts %}
    {% for k, v in base_part.items %}

    {# ...do stuff #}

    {# I try to get a running total of items to use as an ID #}
    inner ID: {% forloop.counter0 %}< br/>
    outer ID: {% forloop.parentloop.counter0 %}< br/>

    {% endfor %}
{% endfor %}

如您所见,我想要的是我已迭代的项目总数的运行总数,但我包含的两种方法都返回重复项。我知道我可以连接循环,但我使用的是表单集,真的希望 id 被索引为 0,1,2...等。

有没有办法在模板中实现这种类型的计数?

非常感谢任何帮助。

编辑

此时的输出如下:

outerID: 0<br />
innerID: 0<br />
outerID: 0<br />
innerID: 1<br />
outerID: 1<br />
innerID: 0<br />
outerID: 1<br />
innerID: 1<br />
outerID: 1<br />
innerID: 2<br />

我想要:

totalID: 0<br />
totalID: 1<br />
totalID: 2<br />
totalID: 3<br />
totalID: 4<br />
totalID: 5<br />
totalID: 6<br />
totalID: 7<br />
totalID: 8<br />
totalID: 9<br />

【问题讨论】:

  • 你会发布你收到的输出和你期望收到的输出吗?

标签: django django-templates


【解决方案1】:

我通过itertools 找到了更好的解决方案。 (比我之前的回答好) 您可以将循环的当前状态设置为发送到视图上下文的 itertools 变量。 这次我尝试了一个虚拟的 Django 项目,它就像一个魅力。

views.py:

from django.shortcuts import render_to_response
import itertools

def home(request):
    iterator=itertools.count()
    base_parts = [
        {'important item': 43},
        {'lesser item1': 22, 'lesser item2': 3, 'lesser item3': 45},
        {'most important item': 55}
    ]
    return render_to_response('index.html', 
                             {'base_parts': base_parts, 'iterator':iterator})

index.html:

{% for base_part in base_parts %}
    {% for k, v in base_part.items %}
        {{ iterator.next }} - {{ v }}<br/>
    {% endfor %}
{% endfor %}

HTML 输出:

0 - 43
1 - 22
2 - 45
3 - 3
4 - 55

排序值:

(这部分不是对实际问题的回答。更像是在玩弄)

您可以使用 Django 的 SortedDict 代替 Python 的内置字典来保持项目的顺序。

views.py

from django.shortcuts import render_to_response
import itertools
from django.utils.datastructures import SortedDict

def home(request):
    iterator=itertools.count()
    base_parts = [
        SortedDict([('important item', 43)]),
        SortedDict([('lesser item1', 22), 
                    ('lesser item2', 3), 
                    ('lesser item3', 45)]),
        SortedDict([('most important item', 55)])
    ]
    print base_parts[1]
    return render_to_response('index.html', 
                             {'base_parts': base_parts, 'iterator':iterator})

HTML 输出:

0 - 43
1 - 22
2 - 3
3 - 45
4 - 55

编辑 2014 年 5 月 25 日

您也可以使用collections.OrderedDict 代替 Django 的 SortedDict。

2016 年 6 月 28 日编辑

调用iterator.next 在 Python 3 中不起作用。您可以创建自己的迭代器类,继承自 itertools.count:

import itertools
class TemplateIterator(itertools.count):
    def next(self):
        return next(self)

【讨论】:

  • 酷!与作业标签一起使用非常好! @register.assignment_tag \n def get_counter(start=1): \n return itertools.count(start)
【解决方案2】:

所以我实际上只是将字典项附加到一个列表中,确保我想要的是第一个:

base_parts = []
for k, v in rails_dic.items():
    base_parts.append({k: v})
for k, v in accessories_dic.items():
    base_parts.append({k: v})

这可能不是最好的方法,我愿意以更 Python 的方式作为正确答案

我认为在模板中处理这个问题既棘手又不合适。这就是我不接受这些答案的原因。我希望未来的访问者可以看到以更正确的方式寻求整体问题的解决方案,而不仅仅是如何在模板中破解它。

【讨论】:

    【解决方案3】:

    在理想情况下,您应该避免将这种逻辑放在模板中。如果您没有在输出中保留层次结构(例如,将这些项目显示为列表列表),请展平列表并使用简单的 for 循环和循环计数器。

    但是,理想的解决方案并不总是一种选择。从理论上讲,我相信以下可以/应该工作

    {% for base_part in base_parts %}     
        {% with outerCount = forloop.parentloop.counter0 %}
        {% for k, v in base_part.items %}
            ...
            {% with innerCounter = forloop.counter %}
            {{ outerCounter|add:innerCounter }}
        {% endfor %}
    {% endfor %}
    

    【讨论】:

      【解决方案4】:

      在视图代码中这样做会非常有效......

          #Calculate the count
          count = 0
          for item in base_parts:
             count+=len(item.keys())
      
          run_range = range(count)
      
          return to the template
      
          #template
          {% for x in run_range|slice:'1' %}
          {{x}}
          {% endfor %}
      

      【讨论】:

        【解决方案5】:

        更新:这不是一个正确的答案。我只是将它放在这里以显示 不起作用 的功能。

        我不得不承认我没有尝试过这个,但你可以使用withadd 语句。

        {% with total=0 %}
            {% for base_part in base_parts %}
                {% for k, v in base_part.items %}
        
                {# ...do stuff #}
        
                {# I try to get a running total of items to use as an ID #}
                totalId: {{ total|add:"1" }} <br/>
                {% endfor %}
            {% endfor %}
        {% endwith %}
        

        这可能适用于模板级别但我认为更好的方法是在视图级别计算它并将字典传递给包含计算值的模板。

        【讨论】:

        • 但这永远不会改变total的值——它只是加了1。
        • 那么这是一个糟糕的答案。我认为它可能会起作用。但正如 Django 模板哲学所暗示的那样:the template system is meant to express presentation, not program logic. 我们必须遵循这些规则。因此计算视图中的列表项并将该对象传递给模板将是一种更好的方法。
        • 是的,在模板中这似乎太多了。我认为更好的方法是将字典列表编译为字典列表,其中列表中的每个元素都是一个键值对。
        猜你喜欢
        • 2012-10-25
        • 2021-05-23
        • 1970-01-01
        • 2012-06-11
        • 2021-05-07
        • 2020-10-30
        • 2020-08-03
        • 1970-01-01
        • 2019-05-23
        相关资源
        最近更新 更多