Numerico per loop nei modelli Django


261

Come faccio a scrivere un forciclo numerico in un modello Django? Intendo qualcosa del genere

for i = 1 to n

Risposte:


392

Ho usato una tecnica semplice che funziona bene per casi piccoli senza tag speciali e senza contesto aggiuntivo. A volte questo è utile

{% for i in '0123456789'|make_list %}
    {{ forloop.counter }}
{% endfor %}

9
FWIW, 012 == 12, quindi passerà in loop solo su 1 e 2.
jason

22
{% for i in '0123456789' | make_list%} per scorrere su tutti i 10, senza saltare 0.
Rick,

7
Genera una stringa di lunghezza arbitraria con 'rjust'{% for i in "x"|rjust:"100" %}
Aaron

27
Per la terza volta, questa risposta è MALE . NON usare questo. Utilizzare un tag modello e farlo correttamente. Non riesco a vedere come dire una risposta sia negativa, è una ragione sufficiente per eliminare un commento.
Rebs,

6
@Rebs Cosa c'è di male in questo? Certo, è un po 'confuso, ma l'aggiunta di un tag modello solo perché è necessario eseguire il ciclo su un intervallo ridotto per una volta in un progetto non è una soluzione altrettanto eccezionale.
tobltobs,

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

9
Bella risposta. Funziona perché center crea una stringa di n spazi che vengono quindi sottoposti a loop. Ogni carattere spaziale viene quindi ignorato, ma il valore corrente nell'intervallo può essere trovato da forloop.counter (o forloop.counter0). Vedi docs.djangoproject.com/en/dev/ref/templates/builtins/#center
isedwards

2
Bella risposta! Non è stato necessario creare un nuovo filtro.
Miguel Ike,

Non c'è bisogno di fare nulla in vista. Eccellente hack
Mohammed Shareef C

106

Sfortunatamente, questo non è supportato nel linguaggio dei template di Django. Ci sono un paio di suggerimenti , ma sembrano un po 'complessi. Vorrei solo inserire una variabile nel contesto:

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

e nel modello:

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

13
Le motivazioni che gli autori di Django hanno avuto per vietare il semplice pitone nei modelli sembrano inutili e insignificanti rispetto al dolore e al tempo perso nel lavorare per non averlo, per non parlare della necessità di inventare un langauge completamente nuovo quando perfettamente perfetto (pitone! ) è già lì!
Bogatyr,

2
@Bogatyr Se è quello che vuoi, usa Jinja2: docs.djangoproject.com/en/1.9/topics/templates/…
fino

78

La mia opinione su questo problema, penso che sia il migliore. Tengo un my_filters.py nella directory templatetags.

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

E useresti così:

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

1
Penso che questa sia la soluzione giusta. Fai range(1, 16)per ottenere numeri a partire da 1, non da 0.
chhantyal

Crea anche un file vuoto _ init _.py nella directory templatetags. Aggiungi anche queste righe all'inizio di my_filters.py from django.template import Library;register = Library()
Ajeeb.KP

Aggiungi un secondo parametro di filtro e ottieni la funzione full range integrata in Python. @register.filter(name='range') def filter_range(start, end): return range(start, end)Quindi si abitua come {% for i in 1|range:6 %}{% endfor %}. Vedi la risposta completa di seguito ....
Paul Kenjora,

Ho modificato questo un po '(scusate la formattazione): try: return range(number) except: return []. In questo modo non genera mai un errore e restituisce un array vuoto (simile a come funzionano la maggior parte delle funzioni del modello).
Tim Tisdall,


41

Puoi passare un'associazione di

{'n' : range(n) }

al modello, quindi esegui

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

Nota che otterrai un comportamento basato su 0 (0, 1, ... n-1).

(Aggiornato per la compatibilità con Python3)


1
Usa range(n)in Python 3, se lo ricordo correttamente, xrange è stato deprecato su di esso
Felício

Si, certo. E quella era una delle due righe di codice che ho avuto la possibilità di trasferire un'app su Python3.
Dave W. Smith,

9

Non passi da nsolo, ma piuttosto range(n)[l'elenco di numeri interi compresi tra 0 e n-1], dalla tua vista al tuo modello, e in quest'ultimo {% for i in therange %}caso (se insisti assolutamente su 1 basato anziché sul normale 0 basato sull'indice che puoi usare forloop.counternel corpo del loop ;-).


9

Nel caso in cui qualcuno si imbattesse in questa domanda ... Ho creato un tag modello che ti consente di creare un range(...): http://www.djangosnippets.org/snippets/1926/

Accetta gli stessi argomenti del 'range' incorporato e crea un elenco contenente
il risultato di "range".

Sintassi:
    {% mkrange [start,] stop [, step] come context_name%}

Per esempio:
    {% mkrange 5 10 2 as some_range%}
    {% for i in some_range%}
      {{i}}: Qualcosa che voglio ripetere \ n
    {% endfor%}

produce:
    5: Qualcosa che voglio ripetere 
    7: Qualcosa che voglio ripetere 
    9: Qualcosa che voglio ripetere


1
-1 a favore dello snippet di Alex Pi che aggiunge il supporto di argomenti variabili.
m000,

9

Ho provato molto su questa domanda e trovo la risposta migliore qui: (da come eseguire 7 cicli nei template di django )

Puoi persino accedere a idx!

views.py:

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

html:

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

9

Puoi passare:

{'n': range (n)}

Per utilizzare il modello:

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


leggibile e semplice, facile capire cosa sta succedendo se sei il prossimo a mantenere il codice
rossdavidh,

7

Dovresti usare " slice " nel modello, un esempio come questo:

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>

1
Non sono sicuro se questo è ciò che l'OP stava cercando, ma è esattamente quello che stavo cercando. =)
GChorn

7

Questo metodo supporta tutte le funzionalità della range([start,] stop[, step])funzione standard

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

Produzione

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

la tua soluzione non funziona for value in 0|range:"10,2". Devi cambiare il tuo codice come segue:args = filter(lambda x: isinstance(x, int) and x >= 0, (_min, _max, _step))
Bedilbek,

@Bedilbek questo codice imita la gamma standard di Python. anche se non supporta intervalli negativi senza un parametro step esplicito. >>> list (range (10,2)) [] >>> list (range (10,2, -1)) [10, 9, 8, 7, 6, 5, 4, 3]
Rebs

5

Sto solo prendendo un po 'più in là la risposta popolare e la sto rendendo più solida. Ciò consente di specificare qualsiasi punto iniziale, ad esempio 0 o 1. Utilizza anche la funzione di intervallo di Python in cui la fine è una in meno, quindi può essere utilizzata direttamente con lunghezze di elenco, ad esempio.

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

Quindi nel modello è sufficiente includere il file tag modello sopra riportato e utilizzare quanto segue:

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

Ora puoi fare 1-6 invece di solo 0-6 o codificarlo a fondo. L'aggiunta di un passaggio richiederebbe un tag modello, questo dovrebbe coprire più casi d'uso quindi è un passo avanti.


Questa è un'estensione della risposta di @ guillermo-siliceo-trueba.
Paul Kenjora,

5

Ciò richiede essenzialmente una rangefunzione. A questo scopo è stato generato un ticket funzione Django ( https://code.djangoproject.com/ticket/13088 ) ma chiuso come "non risolto" con il seguente commento.

La mia impressione di questa idea è che sta cercando di condurre alla programmazione nel modello. Se si dispone di un elenco di opzioni che devono essere visualizzate, dovrebbero essere calcolate nella vista, non nel modello. Se è semplice come un intervallo di valori, allora sia così.

Hanno un buon punto: i modelli dovrebbero essere rappresentazioni molto semplici della vista. È necessario creare i dati richiesti limitati nella vista e passare al modello nel contesto.


6
La vista dovrebbe essere per i dati, il modello dovrebbe essere per la presentazione. La vista non dovrebbe richiedere la conoscenza dei contenuti del modello, in particolare degli intervalli. La ragione di Django per ignorare queste richieste di funzionalità è la totale spazzatura.
Rebs,

3

Puoi usare: {% with ''|center: i as range %}


1
Potete fornire un esempio / spiegazione di come funziona?
Rebs,

1

Se il numero proviene da un modello, ho scoperto che questa è una bella patch per il modello:

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

2
Non sono sicuro del motivo per cui stai per essere votato, è una risposta valida. Non mi piace questa soluzione rispetto all'implementazione di un filtro adeguato come ho fornito sopra. I modelli DB devono essere mantenuti snelli. Ma è ancora meglio della risposta accettata dalla maggioranza.
Rebs,

Non so nemmeno ...
Alper,

Sono in ritardo di 9 anni, ma ti ho votato fam, non ti preoccupare nemmeno.
Sahil,

1

Per coloro che cercano una risposta semplice, hanno solo bisogno di visualizzare una quantità di valori, diciamo che 3 su 100 post, ad esempio, basta aggiungerlo {% for post in posts|slice:"3" %}e collegarlo normalmente e verranno aggiunti solo 3 post.


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

{% endfor %}

Mentre questo codice può rispondere alla domanda, fornendo un contesto aggiuntivo riguardo al perché e / o al modo in cui questo codice risponde alla domanda migliora il suo valore a lungo termine.
xiawi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.