Счетчик шаблонов Django в вложенных циклах

Привет, у меня есть список из двух словарей, которые я передаю в шаблон 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 %}

Как вы можете видеть, то, что я хочу, это общее количество общего количества элементов, которые я выполнил, но оба метода, которые я включил, включают дубликаты возврата. Я знаю, что могу конкатенировать циклы, но я использую набор форм и действительно хотел бы, чтобы идентификаторы были проиндексированы 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 />

Ответ 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-май-25

Вы также можете использовать collections.OrderedDict вместо Django SortedDict.

Изменить 2016-июня-28

Вызов iterator.next не работает в Python 3. Вы можете создать свой собственный класс итератора, наследующий от itertools.count:

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

Ответ 2

В идеальном мире вы должны избегать использования такого типа логики в шаблоне. Если вы не сохраняете иерархию в своем выходе (например, отображая эти элементы в виде списка списков), сгладьте список и используйте простой цикл и счетчик циклов.

Однако идеальное решение не всегда является вариантом. В теории я считаю, что следующее может/должно работать

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

Ответ 3

ОБНОВЛЕНИЕ: Это неправильный ответ. Я просто держу его здесь, чтобы показать, что не работает.

Я должен признать, что я не пробовал этот, но вы можете использовать with и add.

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

Это, вероятно, будет работать на уровне шаблона , но я думаю, что лучший подход вычисляет его на уровне представления и передает словарь в шаблон, который включает вычисленные значения.

Ответ 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

Итак, я просто добавил элементы словаря в список, гарантируя, что тот, который я хотел, был первым:

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

Это может быть не лучший способ сделать это, и я открыт более питоническим способом, чем правильный ответ.

Я думаю, что забота об этом в шаблоне является сложной и нецелесообразной. Вот почему я не принимаю эти ответы. Я хотел бы, чтобы будущие посетители могли видеть, что решение было исправлено для общей проблемы более правильным образом, а не только, как взломать ее в шаблонах.