Числовой для цикла в шаблонах Django

261

Как мне написать числовой forцикл в шаблоне Django? Я имею в виду что-то вроде

for i = 1 to n
лев
источник

Ответы:

392

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

{% for i in '0123456789'|make_list %}
    {{ forloop.counter }}
{% endfor %}
Уди
источник
9
FWIW, 012 == 12, поэтому он будет
повторяться
22
{% для i в '0123456789' | make_list%} для итерации по всем 10, не пропуская 0.
Рик
7
Сгенерируйте строку произвольной длины с помощью 'rjust'{% for i in "x"|rjust:"100" %}
Аарон
27
В третий раз этот ответ плохой . НЕ используйте это. Используйте тег шаблона и делайте это правильно. Я не понимаю, как сказать, что ответ плохой, является достаточной причиной, чтобы удалить комментарий.
Ребс
6
@ Rebs Что такого плохого в этом? Конечно, это нехорошо, но добавление тега шаблона только потому, что вам нужно зацикливаться на небольшом диапазоне один раз в проекте, тоже не такое уж хорошее решение.
Tobltobs
114
{% with ''|center:n as range %}
{% for _ in range %}
    {{ forloop.counter }}
{% endfor %}
{% endwith %}
Томаш Живеньевский
источник
9
Отличный ответ. Работает, потому что center создает строку из n пробелов, которые затем зацикливаются. Каждый символ пробела затем игнорируется, но текущее значение в диапазоне можно найти в forloop.counter (или forloop.counter0). См. Docs.djangoproject.com/en/dev/ref/templates/builtins/#center
isedwards
2
Отличный ответ! Не нужно было создавать новый фильтр.
Мигель Айк
Не нужно ничего делать на виду. Отличный хак
Мохаммед Шариф C
106

К сожалению, это не поддерживается в языке шаблонов Django. Есть целый пар из предложений , но они , кажется , немного сложнее. Я бы просто поместил переменную в контекст:

...
render_to_response('foo.html', {..., 'range': range(10), ...}, ...)
...

и в шаблоне:

{% for i in range %}
     ...
{% endfor %}
tghw
источник
13
Мотивы, с помощью которых авторы Django запретили использование простого питона в шаблонах, кажутся бессмысленными и несущественными по сравнению с болью и потерянным временем, связанными с обходом его отсутствия, не говоря уже о необходимости изобретать совершенно новый язык, когда он совершенно потрясающий (питон! ) уже прямо там!
Богатырь
2
@Bogatyr Если это то, что вы хотите, просто используйте Jinja2: docs.djangoproject.com/en/1.9/topics/templates/…
tghw
78

Мой взгляд на этот вопрос, я думаю, самый хороший. Я храню my_filters.py в каталоге templatetags.

@register.filter(name='times') 
def times(number):
    return range(number)

И вы бы использовали так:

{% load my_filters %}
{% for i in 15|times %}
    <li>Item</li>
{% endfor %}
Гильермо Силичео Труба
источник
1
Я думаю, что это правильное решение. Делать, range(1, 16)чтобы получить номера, начиная с 1, а не 0.
chhantyal
Также создайте пустой файл _ init _.py в каталоге templatetags. Также добавьте эти строки в начало my_filters.py from django.template import Library;register = Library()
Ajeeb.KP
Добавьте второй параметр фильтра, и вы получите функцию полного диапазона, встроенную в python. @register.filter(name='range') def filter_range(start, end): return range(start, end)Потом привыкаешь {% for i in 1|range:6 %}{% endfor %}. Смотрите полный ответ ниже ....
Пол Кенджора
Я немного изменил это (извините форматирование) try: return range(number) except: return []. Таким образом, он никогда не вызывает ошибку и возвращает пустой массив (аналогично тому, как работает большинство шаблонных функций).
Тим
41

Может быть так?

{% for i in "x"|rjust:"100" %}
...
{% endfor %}
CruelSilence
источник
41

Вы можете передать обязательство

{'n' : range(n) }

к шаблону, затем сделайте

{% for i in n %}
...
{% endfor %}

Обратите внимание, что вы получите поведение на основе 0 (0, 1, ... n-1).

(Обновлено для совместимости с Python3)

Дейв В. Смит
источник
1
Использование range(n)в Python 3, если я правильно помню, xrange был объявлен устаревшим
Felício
Определенно да. И это была одна из двух строк кода, с которой мне пришлось столкнуться при переносе приложения на Python3.
Дейв У. Смит
9

Вы сами не передаете n, а вместо этого range(n)[список целых чисел от 0 до n-1 включается], от вашего взгляда к вашему шаблону, и в последнем вы делаете {% for i in therange %}(если вы абсолютно настаиваете на 1, а не на нормальном 0 индекс на основе вы можете использовать forloop.counterв теле цикла ;-).

Алекс Мартелли
источник
9

Просто, если кто-то еще сталкивается с этим вопросом ... Я создал тег шаблона, который позволяет вам создать range(...): http://www.djangosnippets.org/snippets/1926/

Принимает те же аргументы, что и встроенный диапазон, и создает список, содержащий
результат «диапазона».

Синтаксис:
    {% mkrange [start,] stop [, step] как context_name%}

Например:
    {% mkrange 5 10 2 as some_range%}
    {% для меня в some_range%}
      {{i}}: то, что я хочу повторить \ n
    {% endfor%}

Производит:
    5: что-то, что я хочу повторить 
    7: что-то, что я хочу повторить 
    9: что-то, что я хочу повторить

Дэвид Волевер
источник
1
-1 в пользу фрагмента Alex Pi, который добавляет поддержку переменных аргументов.
m000
9

Вы можете пройти:

{'n': range (n)}

Чтобы использовать шаблон:

{% для i в n%} ... {% endfor%}

rkoots
источник
удобочитаемым и простым, легко понять, что происходит, если вы следующий парень, поддерживающий код
rossdavidh
7

Вы должны использовать « slice » в шаблоне, например, так:

в views.py

contexts = {
    'ALL_STORES': Store.objects.all(),
}

return render_to_response('store_list.html', contexts, RequestContext(request, processors=[custom_processor]))

в store_list.html:

<ul>
{% for store in ALL_STORES|slice:":10" %}
    <li class="store_item">{{ store.name }}</li>
{% endfor %}
</ul>
Винта
источник
1
Не уверен, что это то, что искал ОП, но это именно то, что я искал. =)
GChorn
7

Этот метод поддерживает все функциональные возможности стандартной range([start,] stop[, step])функции

<app>/templatetags/range.py

from django import template

register = template.Library()


@register.filter(name='range')
def _range(_min, args=None):
    _max, _step = None, None
    if args:
        if not isinstance(args, int):
            _max, _step = map(int, args.split(','))
        else:
            _max = args
    args = filter(None, (_min, _max, _step))
    return range(*args)

Использование:

{% load range %}

<p>stop 5
{% for value in 5|range %}
{{ value }}
{% endfor %}
</p>

<p>start 5 stop 10
{% for value in 5|range:10 %}
{{ value }}
{% endfor %}
</p>

<p>start 5 stop 10 step 2
{% for value in 5|range:"10,2" %}
{{ value }}
{% endfor %}
</p>

Вывод

<p>stop 5
0 1 2 3 4
</p>

<p>start 5 stop 10
5 6 7 8 9
</p>

<p>start 5 stop 10 step 2
5 7 9
</p>
РЭП
источник
Ваше решение не работает for value in 0|range:"10,2". Вы должны изменить свой код следующим образом:args = filter(lambda x: isinstance(x, int) and x >= 0, (_min, _max, _step))
Бедилбек
@Bedilbek этот код имитирует стандартный диапазон Python. даже он не поддерживает отрицательные диапазоны без явного параметра шага. >>> list (range (10,2)) [] >>> list (range (10,2, -1)) [10, 9, 8, 7, 6, 5, 4, 3]
Ребс
5

Я просто продолжаю популярный ответ и делаю его более надежным. Это позволяет вам указать любую начальную точку, например 0 или 1. Он также использует функцию диапазона Python, где конец на единицу меньше, поэтому его можно использовать напрямую с длинами списка, например.

@register.filter(name='range')
def filter_range(start, end):
  return range(start, end)

Затем в свой шаблон просто включите вышеуказанный файл тега шаблона и используйте следующее:

{% for c in 1|range:6 %}
{{ c }}
{% endfor %}

Теперь вы можете делать 1-6 вместо 0-6 или жестко кодировать его. Добавление шага потребует тег шаблона, это должно охватывать больше случаев использования, так что это шаг вперед.

Пол Кенджора
источник
Это расширение ответа @ guillermo-siliceo-trueba.
Пол Кенджора
5

Это по существу требует rangeфункции. Для этого был подан билет на функцию Django ( https://code.djangoproject.com/ticket/13088 ), но он закрыт как "не исправит" со следующим комментарием.

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

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

Аластер МакКормак
источник
6
Представление должно быть для данных, шаблон должен быть для представления. Представление не должно требовать знания содержимого шаблона, в частности диапазонов. Причина, по которой Джанго игнорирует эти запросы, - полная чушь.
Ребс
3

Ты можешь использовать: {% with ''|center: i as range %}

rkoots
источник
1
Можете ли вы привести пример / объяснение того, как это работает?
Ребс
1

Если число исходит от модели, я обнаружил, что это хороший патч для модели:

def iterableQuantity(self):
    return range(self.quantity)
Alper
источник
2
Не уверен, почему вы проголосовали, это правильный ответ. Мне не нравится это решение по сравнению с реализацией правильного фильтра, как я предоставил выше. Модели БД должны быть сухими. Но это все же лучше, чем принятый большинством ответ.
Ребс
Я даже не знаю…
Альпер
Я опоздал на 9 лет, но я проголосовал за тебя, даже не беспокойся об этом.
Сахиль,
1

Для тех, кто ищет простой ответ, просто нужно отобразить количество значений, скажем, 3 из 100 сообщений, например, просто добавьте {% for post in posts|slice:"3" %}и зациклите его как обычно, и будут добавлены только 3 сообщения.

Элиас Прадо
источник
-5
{% for i in range(10) %}
   {{ i }}

{% endfor %}
Мухаммед Абдулла
источник
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, почему и / или как этот код отвечает на вопрос, повышает его долгосрочную ценность.
xiawi