296
votes

How do I write a numeric for loop in a Django template? I mean something like

for i = 1 to n
20

20 Answers

424
votes

I've used a simple technique that works nicely for small cases with no special tags and no additional context. Sometimes this comes in handy

{% for i in '0123456789'|make_list %}
    {{ forloop.counter }}
{% endfor %}
138
votes
{% with ''|center:n as range %}
{% for _ in range %}
    {{ forloop.counter }}
{% endfor %}
{% endwith %}
114
votes

Unfortunately, that's not supported in the Django template language. There are a couple of suggestions, but they seem a little complex. I would just put a variable in the context:

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

and in the template:

{% for i in range %}
     ...
{% endfor %}
97
votes

My take on this issue, i think is the most pythonic. Create a my_filters.py in your apps templatetags directory.

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

Usage in your template:

{% load my_filters %}
{% for i in 15|times %}
    <li>Item</li>
{% endfor %}
45
votes

You can pass a binding of

{'n' : range(n) }

to the template, then do

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

Note that you'll get 0-based behavior (0, 1, ... n-1).

(Updated for Python3 compatibility)

43
votes

Maybe like this?

{% for i in "x"|rjust:"100" %}
...
{% endfor %}
13
votes

You can pass :

{ 'n' : range(n) }

To use template :

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

10
votes

You don't pass n itself, but rather range(n) [the list of integers from 0 to n-1 included], from your view to your template, and in the latter you do {% for i in therange %} (if you absolutely insist on 1-based rather than the normal 0-based index you can use forloop.counter in the loop's body;-).

10
votes

I tried very hard on this question, and I find the best answer here: (from how to loop 7 times in the django templates)

You can even access the idx!

views.py:

context['loop_times'] = range(1, 8)

html:

{% for i in loop_times %}
        <option value={{ i }}>{{ i }}</option>
{% endfor %}
9
votes

Just incase anyone else comes across this question… I've created a template tag which lets you create a range(...): http://www.djangosnippets.org/snippets/1926/

Accepts the same arguments as the 'range' builtin and creates a list containing
the result of 'range'.

Syntax:
    {% mkrange [start,] stop[, step] as context_name %}

For example:
    {% mkrange 5 10 2 as some_range %}
    {% for i in some_range %}
      {{ i }}: Something I want to repeat\n
    {% endfor %}

Produces:
    5: Something I want to repeat 
    7: Something I want to repeat 
    9: Something I want to repeat

8
votes

This method supports all the functionality of the standard range([start,] stop[, step]) function

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

Usage:

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

Output

<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>
8
votes

I'm just taking the popular answer a bit further and making it more robust. This lets you specify any start point, so 0 or 1 for example. It also uses python's range feature where the end is one less so it can be used directly with list lengths for example.

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

Then in your template just include the above template tag file and use the following:

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

Now you can do 1-6 instead of just 0-6 or hard coding it. Adding a step would require a template tag, this should cover more uses cases so it's a step forward.

7
votes

You should use "slice" in template, a example like this:

in views.py

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

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

in store_list.html:

<ul>
{% for store in ALL_STORES|slice:":10" %}
    <li class="store_item">{{ store.name }}</li>
{% endfor %}
</ul>
5
votes

This essentially requires a range function. A Django feature ticket was raised (https://code.djangoproject.com/ticket/13088) for this but closed as "won't fix" with the following comment.

My impression of this idea is that it is trying to lead to programming in the template. If you have a list of options that need to be rendered, they should be computed in the view, not in the template. If that's as simple as a range of values, then so be it.

They have a good point - Templates are supposed to be very simple representations of the view. You should create the limited required data in the view and pass to the template in the context.

3
votes

If the number is coming from a model, I found this to be a nice patch to the model:

def iterableQuantity(self):
    return range(self.quantity)
3
votes

You can use: {% with ''|center: i as range %}

3
votes

For those who are looking to simple answer, just needing to display an amount of values, let say 3 from 100 posts for example just add {% for post in posts|slice:"3" %} and loop it normally and only 3 posts will be added.

3
votes

This shows 1 to 20 numbers:

{% for i in "x"|rjust:"20"|make_list %}
 {{ forloop.counter }}
{% endfor %}

also this can help you: (count_all_slider_objects come from views)

{% for i in "x"|rjust:count_all_slider_objects %}
  {{ forloop.counter }}
{% endfor %}

or

  {% with counter=count_all_slider_objects %}
    {% if list_all_slider_objects %}
      {%  for slide in list_all_slider_objects %}
        {{forloop.counter|add:"-1"}}
        {% endfor%}
      {% endif %}
    {% endwith %}
0
votes
{% for _ in ''|center:13 %}
    {{ forloop.counter }}
{% endfor %}
-7
votes
{% for i in range(10) %}
   {{ i }}

{% endfor %}