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