Numeryczna dla pętli w szablonach Django

261

Jak napisać forpętlę numeryczną w szablonie Django? Mam na myśli coś takiego

for i = 1 to n
Lew
źródło

Odpowiedzi:

392

Użyłem prostej techniki, która działa dobrze w małych skrzyniach bez specjalnych znaczników i bez dodatkowego kontekstu. Czasami jest to przydatne

{% for i in '0123456789'|make_list %}
    {{ forloop.counter }}
{% endfor %}
Udi
źródło
9
FWIW, 012 == 12, więc będzie zapętlać tylko 1 i 2.
jason
22
{% for i w '0123456789' | make_list%}, aby iterować po wszystkich 10, nie pomijając 0
Rick
7
Wygeneruj ciąg dowolnej długości za pomocą „rjust”{% for i in "x"|rjust:"100" %}
Aaron
27
Po raz trzeci ta odpowiedź jest ZŁA . NIE używaj tego. Użyj tagu szablonu i zrób to poprawnie. Nie rozumiem, jak powiedzenie odpowiedzi jest złe, jest wystarczającym powodem do usunięcia komentarza.
Rebs
6
@Rebs Co jest takiego złego w tym? Pewnie, że jest to hacky, ale dodanie tagu szablonu tylko dlatego, że trzeba raz zapętlić jeden mały zakres w projekcie, nie jest również świetnym rozwiązaniem.
tobltobs
114
{% with ''|center:n as range %}
{% for _ in range %}
    {{ forloop.counter }}
{% endfor %}
{% endwith %}
Tomasz Żyźniewski
źródło
9
Świetna odpowiedź. Działa, ponieważ środek tworzy ciąg n spacji, które są następnie zapętlone. Każdy znak spacji jest następnie ignorowany, ale bieżącą wartość w zakresie można znaleźć w forloop.counter (lub forloop.counter0). Zobacz docs.djangoproject.com/en/dev/ref/templates/builtins/#center
isedwards
2
Świetna odpowiedź! Nie musiałem tworzyć nowego filtra.
Miguel Ike,
Nie trzeba nic robić w widoku. Doskonały hack
Mohammed Shareef C
106

Niestety nie jest to obsługiwane w języku szablonów Django. Istnieje kilka z propozycji , ale wydaje się trochę skomplikowane. Po prostu umieściłbym zmienną w kontekście:

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

i w szablonie:

{% for i in range %}
     ...
{% endfor %}
tghw
źródło
13
Motywacje, które autorzy Django mieli do niedopuszczenia prostego pytona w szablonach, wydają się bezcelowe i nieistotne w porównaniu z bólem i straconym czasem związanym z obejściem go bez niego, nie wspominając już o potrzebie wynalezienia całkowicie nowego języka, gdy jest on niesamowity (python! ) już tam jest!
Bogatyr
2
@Bogatyr Jeśli tego chcesz, po prostu użyj Jinja2: docs.djangoproject.com/en/1.9/topics/templates/…
tghw
78

Uważam, że jest to najlepsze. Trzymam my_filters.py w katalogu templatetags.

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

I użyłbyś takiego:

{% load my_filters %}
{% for i in 15|times %}
    <li>Item</li>
{% endfor %}
Guillermo Siliceo Trueba
źródło
1
Myślę, że to właściwe rozwiązanie. Czy range(1, 16)uzyskać liczby zaczynające się od 1, a nie od 0
chhantyal
Utwórz również pusty plik _ init _.py w katalogu templatetags. Dodaj także tę linię do góry my_filters.py from django.template import Library;register = Library()
Ajeeb.KP
Dodaj drugi parametr filtra, a uzyskasz funkcję pełnego zakresu wbudowaną w python. @register.filter(name='range') def filter_range(start, end): return range(start, end)Następnie przyzwyczaja się jako {% for i in 1|range:6 %}{% endfor %}. Zobacz pełną odpowiedź poniżej ...
Paul Kenjora,
I to nieco zmieniony (przepraszam formatowania) try: return range(number) except: return []. W ten sposób nigdy nie zgłasza błędu i zwraca pustą tablicę (podobnie jak działa większość funkcji szablonu).
Tim Tisdall
41

Może tak?

{% for i in "x"|rjust:"100" %}
...
{% endfor %}
CruelSilence
źródło
41

Możesz przekazać powiązanie

{'n' : range(n) }

do szablonu, a następnie zrób

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

Zauważ, że otrzymasz zachowanie oparte na 0 (0, 1, ... n-1).

(Zaktualizowano dla kompatybilności z Python3)

Dave W. Smith
źródło
1
Użyj range(n)w pythonie 3, jeśli dobrze pamiętam, xrange był na nim przestarzały
Felício
W rzeczy samej tak. I to był jeden z dwóch wierszy kodu, na który musiałem przypadkowo przenieść aplikację do Python3.
Dave W. Smith
9

Nie przekazujesz nsię, ale raczej range(n)[dołączona lista liczb całkowitych od 0 do n-1], z twojego widoku do szablonu, a w tym drugim robisz {% for i in therange %}(jeśli absolutnie nalegasz na 1 zamiast zwykłego 0 oparty na indeksie, którego można użyć forloop.counterw ciele pętli ;-).

Alex Martelli
źródło
9

Wystarczy, że ktokolwiek napotka to pytanie… Stworzyłem tag szablonu, który pozwala ci stworzyć range(...): http://www.djangosnippets.org/snippets/1926/

Akceptuje te same argumenty, co wbudowane „zakres” i tworzy listę zawierającą
wynik „zasięgu”.

Składnia:
    {% mkrange [start,] stop [, krok] jako nazwa_kontekstu%}

Na przykład:
    {% mkrange 5 10 2 as some_range%}
    {% for i in some_range%}
      {{i}}: Coś, co chcę powtórzyć \ n
    {% endfor%}

Produkuje:
    5: Coś, co chcę powtórzyć 
    7: Coś, co chcę powtórzyć 
    9: Coś, co chcę powtórzyć

David Wolever
źródło
1
-1 na korzyść fragmentu Alexa Pi, który dodaje obsługę zmiennych argumentów.
m000
9

Bardzo się starałem na to pytanie i znajduję najlepszą odpowiedź tutaj: (od tego, jak zapętlić 7 razy w szablonach django )

Możesz nawet uzyskać dostęp do idx!

views.py:

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

HTML:

{% for i in loop_times %}
        <option value={{ i }}>{{ i }}</option>
{% endfor %}
KKlalala
źródło
9

Możesz przekazać:

{'n': zakres (n)}

Aby użyć szablonu:

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

rkoots
źródło
czytelny i prosty, łatwy do zrozumienia, co się dzieje, jeśli jesteś kolejnym facetem utrzymującym kod
rossdavidh
7

W szablonie należy użyć „ plasterka ”, na przykład:

w views.py

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

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

w store_list.html:

<ul>
{% for store in ALL_STORES|slice:":10" %}
    <li class="store_item">{{ store.name }}</li>
{% endfor %}
</ul>
Vinta
źródło
1
Nie jestem pewien, czy tego właśnie szukał OP, ale dokładnie tego szukałem. =)
GChorn
7

Metoda ta obsługuje wszystkie funkcje standardowej range([start,] stop[, step])funkcji

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

Stosowanie:

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

Wynik

<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
źródło
Twoje rozwiązanie nie działa for value in 0|range:"10,2". Musisz zmienić kod w następujący sposób:args = filter(lambda x: isinstance(x, int) and x >= 0, (_min, _max, _step))
Bedilbek
@Bedilbek ten kod naśladuje standardowy zakres python. nawet nie obsługuje ujemnych zakresów bez wyraźnego parametru kroku. >>> lista (zakres (10,2)) [] >>> lista (zakres (10,2, -1)) [10, 9, 8, 7, 6, 5, 4, 3]
Rebs
5

Po prostu posuwam popularną odpowiedź nieco dalej i robię ją bardziej niezawodną. Umożliwia to określenie dowolnego punktu początkowego, na przykład 0 lub 1. Używa także funkcji zakresu Pythona, gdzie koniec jest o jeden mniejszy, więc można go użyć bezpośrednio na przykład z długością listy.

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

Następnie w swoim szablonie po prostu dołącz powyższy plik znacznika szablonu i użyj następujących poleceń:

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

Teraz możesz zrobić 1-6 zamiast tylko 0-6 lub kodować na stałe. Dodanie kroku wymagałoby tagu szablonu, który powinien obejmować więcej przypadków użycia, więc jest to krok naprzód.

Paul Kenjora
źródło
To rozszerzenie odpowiedzi @ guillermo-siliceo-trueba.
Paul Kenjora,
5

Zasadniczo wymaga to rangefunkcji. Zgłoszono bilet funkcji Django ( https://code.djangoproject.com/ticket/13088 ), ale zamknięto go jako „nie można naprawić” następującym komentarzem.

Mam wrażenie, że ten pomysł jest taki, że próbuje doprowadzić do programowania w szablonie. Jeśli masz listę opcji, które należy wyrenderować, należy je obliczyć w widoku, a nie w szablonie. Jeśli to tak proste jak zakres wartości, niech tak będzie.

Mają dobrą rację - szablony mają być bardzo prostymi reprezentacjami widoku. Należy utworzyć ograniczone wymagane dane w widoku i przekazać szablon w kontekście.

Alastair McCormack
źródło
6
Widok powinien dotyczyć danych, szablon powinien być przeznaczony do prezentacji. Widok nie powinien wymagać znajomości treści szablonu, a konkretnie zakresów. Powodem ignorowania tych żądań funkcji przez Django jest totalne śmieci.
Rebs
3

Możesz użyć: {% with ''|center: i as range %}

rkoots
źródło
1
Czy możesz podać przykład / wyjaśnienie, jak to działa?
Rebs
1

Dla tych, którzy szukają prostej odpowiedzi, tylko wyświetlającej liczbę wartości, powiedzmy, że na przykład 3 ze 100 postów po prostu dodają {% for post in posts|slice:"3" %}i zapętlają ją normalnie, a zostaną dodane tylko 3 posty.

Elias Prado
źródło
0

Jeśli numer pochodzi z modelu, uważam, że jest to przyjemna łatka do modelu:

def iterableQuantity(self):
    return range(self.quantity)
Alper
źródło
2
Nie jestem pewien, dlaczego przegłosowano, to ważna odpowiedź. Nie podoba mi się to rozwiązanie w porównaniu do implementacji odpowiedniego filtra, jak podałem powyżej. Modele DB powinny pozostać szczupłe. Ale to wciąż lepsze niż większość zaakceptowanych odpowiedzi.
Rebs
Nawet nie wiem ...
Alper
Jestem o 9 lat za późno, ale głosowałem cię, fam, nawet się o to nie martw.
Sahil
-5
{% for i in range(10) %}
   {{ i }}

{% endfor %}
Muhammad Abdullah
źródło
Chociaż ten kod może odpowiedzieć na pytanie, zapewnienie dodatkowego kontekstu dotyczącego tego, dlaczego i / lub jak ten kod odpowiada na pytanie, poprawia jego długoterminową wartość.
xiawi