嵌套循环中的Django模板计数器

时间:2012-12-14 00:24:53

标签: django django-templates

您好我有两个字典的列表,我将传递给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 %}

正如你所看到的,我想要的是我迭代完成的项目总数的总计,但我包含的两种方法都包含返回重复项。我知道我可以连接循环,但我使用的是一个formset,并且真的希望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 />

5 个答案:

答案 0 :(得分:13)

我找到了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)

答案 1 :(得分: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 %}

答案 2 :(得分:1)

更新:这不是正确的答案。我只是在这里显示的工作原理。

我必须承认我没有尝试过这个,但您可以使用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 %}

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

答案 3 :(得分:0)

在视图代码中进行此操作非常有效...

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

答案 4 :(得分:0)

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

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})

这可能不是最好的方法,而且我对正确答案采取更加抒情的方式。

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