Numérico para bucle en plantillas de Django

261

¿Cómo escribo un forbucle numérico en una plantilla de Django? Me refiero a algo como

for i = 1 to n
Lev
fuente

Respuestas:

392

He usado una técnica simple que funciona bien para casos pequeños sin etiquetas especiales y sin contexto adicional. A veces esto es útil.

{% for i in '0123456789'|make_list %}
    {{ forloop.counter }}
{% endfor %}
Udi
fuente
9
FWIW, 012 == 12, por lo que solo se repetirá en 1 y 2.
jason
22
{% para i en '0123456789' | make_list%} para iterar sobre los 10, sin omitir 0.
Rick
77
Genere una cadena de longitud arbitraria con 'rjust'{% for i in "x"|rjust:"100" %}
Aaron
27
Por tercera vez, esta respuesta es MALA . NO utilices esto. Use una etiqueta de plantilla y hágalo correctamente. No veo cómo decir que una respuesta es mala, es razón suficiente para eliminar un comentario.
Rebs
66
@Rebs ¿Qué tiene de malo esto? Claro que es hacky, pero agregar una etiqueta de plantilla solo porque necesita recorrer un rango pequeño por una vez en un proyecto tampoco es una gran solución.
tobltobs
114
{% with ''|center:n as range %}
{% for _ in range %}
    {{ forloop.counter }}
{% endfor %}
{% endwith %}
Tomasz Żyźniewski
fuente
9
Gran respuesta. Funciona porque el centro crea una cadena de n espacios que luego se repiten. Cada espacio de caracteres se ignora, pero el valor actual en el rango se puede encontrar en forloop.counter (o forloop.counter0). Ver docs.djangoproject.com/en/dev/ref/templates/builtins/#center
isedwards
2
¡Gran respuesta! No tuve que crear un nuevo filtro.
Miguel Ike
No es necesario hacer nada a la vista. Hack excelente
Mohammed Shareef C
106

Desafortunadamente, eso no es compatible con el lenguaje de plantilla Django. Hay un par de sugerencias , pero parecen un poco complejas. Simplemente pondría una variable en el contexto:

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

y en la plantilla:

{% for i in range %}
     ...
{% endfor %}
tghw
fuente
13
Las motivaciones que tuvieron los autores de Django para rechazar Python simple en plantillas parecen inútiles e intrascendentes en comparación con el dolor y el tiempo perdido involucrados en trabajar para no tenerlo, sin mencionar la necesidad de inventar un lenguaje completamente nuevo cuando uno perfectamente increíble (¡Python! ) ya está ahí!
Bogatyr
2
@Bogatyr Si eso es lo que quieres, solo usa Jinja2: docs.djangoproject.com/en/1.9/topics/templates/…
tghw
78

Mi opinión sobre este tema, creo que es la mejor. Mantengo my_filters.py en el directorio templatetags.

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

Y usarías así:

{% load my_filters %}
{% for i in 15|times %}
    <li>Item</li>
{% endfor %}
Guillermo Siliceo Trueba
fuente
1
Creo que esta es la solución correcta. Para range(1, 16)obtener números a partir del 1, no del 0.
chhantyal
También cree un archivo vacío _ init _.py en el directorio templatetags. Agregue también estas líneas en la parte superior de my_filters.py from django.template import Library;register = Library()
Ajeeb.KP
Agregue un segundo parámetro de filtro y obtendrá la función de rango completo integrada en python. @register.filter(name='range') def filter_range(start, end): return range(start, end)Luego se acostumbra como {% for i in 1|range:6 %}{% endfor %}. Vea la respuesta completa a continuación ...
Paul Kenjora
Alteré esta ligeramente (con perdón de formatear): try: return range(number) except: return []. De esa manera, nunca genera un error y devuelve una matriz vacía (similar a cómo funciona la mayoría de las funciones de plantilla).
Tim Tisdall
41

Tal vez así?

{% for i in "x"|rjust:"100" %}
...
{% endfor %}
CruelSilence
fuente
41

Puede pasar un enlace de

{'n' : range(n) }

a la plantilla, luego haz

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

Tenga en cuenta que obtendrá un comportamiento basado en 0 (0, 1, ... n-1).

(Actualizado para compatibilidad con Python3)

Dave W. Smith
fuente
1
Uso range(n)en python 3, si no recuerdo mal, xrange fue desaprobado
Felício
De hecho si. Y esa fue una de las dos líneas de código que tuve la oportunidad de hacer una transición de una aplicación a Python3.
Dave W. Smith
9

No se pasa a nsí mismo, sino más bien range(n)[incluye la lista de enteros de 0 a n-1], desde su punto de vista hasta su plantilla, y en el último lo hace {% for i in therange %}(si insiste absolutamente en 0 basado en 1 en lugar del 0 normal) basado en índices que puede usar forloop.counteren el cuerpo del bucle ;-).

Alex Martelli
fuente
9

En caso de que alguien más se encuentre con esta pregunta ... He creado una etiqueta de plantilla que le permite crear range(...): http://www.djangosnippets.org/snippets/1926/

Acepta los mismos argumentos que el 'rango' integrado y crea una lista que contiene
El resultado de 'rango'.

Sintaxis:
    {% mkrange [inicio,] parada [, paso] como context_name%}

Por ejemplo:
    {% mkrange 5 10 2 como some_range%}
    {% para i en some_range%}
      {{i}}: Algo que quiero repetir \ n
    {% endfor%}

Produce:
    5: algo que quiero repetir 
    7: algo que quiero repetir 
    9: algo que quiero repetir

David Wolever
fuente
1
-1 a favor del fragmento de Alex Pi que agrega soporte de argumentos variables.
m000
9

Intenté mucho esta pregunta, y encuentro la mejor respuesta aquí: (de cómo recorrer 7 veces en las plantillas de django )

¡Incluso puedes acceder al idx!

views.py:

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

html:

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

Puedes pasar :

{'n': rango (n)}

Para usar la plantilla:

{% para i en n%} ... {% endfor%}

rkoots
fuente
legible y simple, fácil de entender lo que está pasando, si usted es el tipo de al lado mantener el código
rossdavidh
7

Deberías usar " slice " en la plantilla, un ejemplo como este:

en views.py

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

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

en store_list.html:

<ul>
{% for store in ALL_STORES|slice:":10" %}
    <li class="store_item">{{ store.name }}</li>
{% endfor %}
</ul>
Vinta
fuente
1
No estoy seguro de si esto es lo que estaba buscando el OP, pero es exactamente lo que estaba buscando. =)
GChorn
7

Este método admite toda la funcionalidad de la range([start,] stop[, step])función estándar .

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

Uso:

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

Salida

<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
fuente
su solución no funciona for value in 0|range:"10,2". args = filter(lambda x: isinstance(x, int) and x >= 0, (_min, _max, _step))
Debe
@Bedilbek, este código imita el rango estándar de Python. incluso no admite rangos negativos sin un parámetro de paso explícito. >>> lista (rango (10,2)) [] >>> lista (rango (10,2, -1)) [10, 9, 8, 7, 6, 5, 4, 3]
Rebs
5

Solo estoy llevando la respuesta popular un poco más allá y haciéndola más robusta. Esto le permite especificar cualquier punto de inicio, por ejemplo, 0 o 1. También usa la función de rango de Python donde el final es uno menos, por lo que puede usarse directamente con longitudes de lista, por ejemplo.

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

Luego, en su plantilla, simplemente incluya el archivo de etiqueta de plantilla anterior y use lo siguiente:

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

Ahora puede hacer 1-6 en lugar de solo 0-6 o codificarlo. Agregar un paso requeriría una etiqueta de plantilla, esto debería cubrir más casos de uso, por lo que es un paso adelante.

Paul Kenjora
fuente
Esta es una extensión de la respuesta @ guillermo-siliceo-trueba.
Paul Kenjora
5

Esto esencialmente requiere una rangefunción. Se generó un ticket de función de Django ( https://code.djangoproject.com/ticket/13088 ) para esto, pero se cerró como "no se solucionará" con el siguiente comentario.

Mi impresión de esta idea es que está tratando de conducir a la programación en la plantilla. Si tiene una lista de opciones que deben representarse, deben calcularse en la vista, no en la plantilla. Si eso es tan simple como un rango de valores, entonces que así sea.

Tienen un buen punto: se supone que las plantillas son representaciones muy simples de la vista. Debe crear los datos requeridos limitados en la vista y pasarlos a la plantilla en el contexto.

Alastair McCormack
fuente
66
La vista debe ser para datos, la plantilla debe ser para presentación. La vista no debe requerir el conocimiento del contenido de la plantilla, específicamente los rangos. La razón de Django para ignorar estas solicitudes de características es una basura total.
Rebs
3

Puedes usar: {% with ''|center: i as range %}

rkoots
fuente
1
¿Puede proporcionar un ejemplo / explicación de cómo funciona esto?
Rebs
1

Si el número proviene de un modelo, creo que este es un buen parche para el modelo:

def iterableQuantity(self):
    return range(self.quantity)
Alper
fuente
2
No estoy seguro de por qué te van a votar, es una respuesta válida. No me gusta esta solución en comparación con la implementación de un filtro adecuado como he proporcionado anteriormente. Los modelos DB deben mantenerse delgados. Pero aún es mejor que la respuesta aceptada por la mayoría.
Rebs
Ni siquiera sé ...
Alper
Llegué 9 años demasiado tarde, pero te voté fam, ni siquiera te preocupes por eso.
Sahil
1

Para aquellos que buscan una respuesta simple, solo necesitan mostrar una cantidad de valores, digamos 3 de 100 publicaciones, por ejemplo, simplemente agreguen {% for post in posts|slice:"3" %}y repita normalmente y solo se agregarán 3 publicaciones.

Elias Prado
fuente
-5
{% for i in range(10) %}
   {{ i }}

{% endfor %}
Muhammad Abdullah
fuente
Si bien este código puede responder la pregunta, proporcionar un contexto adicional con respecto a por qué y / o cómo responde la pregunta mejora su valor a largo plazo.
xiawi