[Django]-Numeric for loop in Django templates

484πŸ‘

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 %}
πŸ‘€Udi

172πŸ‘

{% with ''|center:n as range %}
{% for _ in range %}
    {{ forloop.counter }}
{% endfor %}
{% endwith %}

123πŸ‘

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 %}
πŸ‘€tghw

118πŸ‘

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

53πŸ‘

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)

πŸ‘€Dave W. Smith

52πŸ‘

Maybe like this?

{% for i in "x"|rjust:"100" %}
...
{% endfor %}
πŸ‘€CruelSilence

20πŸ‘

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:

{% load myapp_filters %}

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

πŸ‘€Paul Kenjora

14πŸ‘

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 %}
πŸ‘€KKlalala

11πŸ‘

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

πŸ‘€Alex Martelli

10πŸ‘

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

πŸ‘€David Wolever

10πŸ‘

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>
πŸ‘€Vinta

10πŸ‘

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>
πŸ‘€Rebs

5πŸ‘

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.

4πŸ‘

{% for _ in ''|center:13 %}
    {{ forloop.counter }}
{% endfor %}

3πŸ‘

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)
πŸ‘€Alper

3πŸ‘

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.

πŸ‘€Elias Prado

3πŸ‘

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 %}
πŸ‘€Darwin

1πŸ‘

If you work with queryset you can cap the number of elements with if.
Assume that you need to list 5 items:

{% for  item in queryset %}
  {% if forloop.counter < 6 %}
   {{ forloop.counter}}.{{item}}
  {% endif %}
{% endfor %}

If you need just number range, I think its better to create a list or tuple on view part and then push it to the template.

On view:

iteration = [item for item in range(10)]
context= {'iteration':iteration}

On Template:

{% for  item in iteration %}
  {{ forloop.counter}}.{{item}}
{% endfor %}
πŸ‘€Alkindus

0πŸ‘

You can pass range(n) instead of n in the context in views.py. This will give you an iterable list.

context['range']= range(n)

Then you can iterate in your template this way:

{% for i in range %}
   <!-- your code -->
{% endfor %}
πŸ‘€Srishti Ahuja

-13πŸ‘

{% for i in range(10) %}
   {{ i }}

{% endfor %}

Leave a comment