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

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

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

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

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

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

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)


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


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


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


9

Puedes pasar :

{'n': rango (n)}

Para usar la plantilla:

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


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>

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>

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.


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.


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


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)

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.


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

{% endfor %}

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.