Numerik untuk loop dalam template Django

261

Bagaimana cara menulis forlingkaran angka dalam template Django? Maksud saya sesuatu seperti

for i = 1 to n
Im
sumber

Jawaban:

392

Saya telah menggunakan teknik sederhana yang bekerja dengan baik untuk kasus-kasus kecil tanpa tag khusus dan tanpa konteks tambahan. Terkadang ini berguna

{% for i in '0123456789'|make_list %}
    {{ forloop.counter }}
{% endfor %}
Udi
sumber
9
FWIW, 012 == 12, jadi itu hanya akan berulang 1 dan 2.
jason
22
{% for i in '0123456789' | make_list%} untuk beralih ke semua 10, tidak melewatkan 0.
Rick
7
Hasilkan string dengan panjang sewenang-wenang dengan 'rjust'{% for i in "x"|rjust:"100" %}
Aaron
27
Untuk ketiga kalinya, jawaban ini BURUK . JANGAN gunakan ini. Gunakan tag templat dan lakukan dengan benar. Saya gagal melihat bagaimana mengatakan jawaban itu buruk, cukup alasan untuk menghapus komentar.
Rebs
6
@Rebs Apa yang sangat buruk dengan ini? Tentu itu hacky, tetapi menambahkan tag templat hanya karena Anda perlu mengulangi rentang kecil untuk satu kali dalam suatu proyek bukan solusi yang hebat juga.
tobltobs
114
{% with ''|center:n as range %}
{% for _ in range %}
    {{ forloop.counter }}
{% endfor %}
{% endwith %}
Tomasz Żyźniewski
sumber
9
Jawaban yang bagus Berfungsi karena pusat membuat string n spasi yang kemudian di-looped. Setiap karakter spasi kemudian diabaikan, tetapi nilai saat ini dalam rentang dapat ditemukan dari forloop.counter (atau forloop.counter0). Lihat docs.djangoproject.com/en/dev/ref/templates/builtins/#center
isedwards
2
Jawaban bagus! Tidak harus membuat filter baru.
Miguel Ike
Tidak perlu melakukan apa pun dalam tampilan. Retasan luar biasa
Mohammed Shareef C
106

Sayangnya, itu tidak didukung dalam bahasa template Django. Ada beberapa dari saran , tetapi mereka tampak sedikit rumit. Saya hanya akan meletakkan variabel dalam konteks:

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

dan di templat:

{% for i in range %}
     ...
{% endfor %}
tghw
sumber
13
Motivasi yang dimiliki penulis Django untuk melarang python biasa dalam templat tampaknya tidak ada gunanya dan tidak penting dibandingkan dengan rasa sakit dan kehilangan waktu yang diperlukan untuk bekerja dengan tidak memilikinya, belum lagi kebutuhan untuk menciptakan bahasa yang sama sekali baru ketika bahasa python yang benar-benar hebat (python! ) sudah ada di sana!
Bogatyr
2
@Bogatyr Jika itu yang Anda inginkan, hanya menggunakan Jinja2: docs.djangoproject.com/en/1.9/topics/templates/...
tghw
78

Pandangan saya tentang masalah ini, saya pikir adalah yang terbaik. Saya menyimpan my_filters.py di direktori templatetags.

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

Dan Anda akan menggunakan seperti ini:

{% load my_filters %}
{% for i in 15|times %}
    <li>Item</li>
{% endfor %}
Guillermo Siliceo Trueba
sumber
1
Saya pikir ini solusi yang tepat. Lakukan range(1, 16)untuk mendapatkan angka mulai dari 1, bukan 0.
chhantyal
Juga buat file kosong _ init _.py di direktori templatetags. Tambahkan juga baris ini ke atas my_filters.py from django.template import Library;register = Library()
Ajeeb.KP
Tambahkan parameter filter kedua dan Anda mendapatkan fungsi rentang penuh dibangun menjadi python. @register.filter(name='range') def filter_range(start, end): return range(start, end)Kemudian akan digunakan sebagai {% for i in 1|range:6 %}{% endfor %}. Lihat jawaban lengkap di bawah ini ....
Paul Kenjora
Saya mengubah ini sedikit (maaf format): try: return range(number) except: return []. Dengan cara itu tidak pernah memunculkan kesalahan dan mengembalikan array kosong (mirip dengan cara sebagian besar fungsi templat bekerja).
Tim Tisdall
41

Mungkin seperti ini

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

Anda dapat melewati pengikatan

{'n' : range(n) }

ke template, lalu lakukan

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

Perhatikan bahwa Anda akan mendapatkan perilaku berbasis 0 (0, 1, ... n-1).

(Diperbarui untuk kompatibilitas Python3)

Dave W. Smith
sumber
1
Gunakan range(n)dalam python 3, jika saya mengingatnya dengan benar, xrange sudah tidak digunakan lagi
Felício
Ya benar. Dan itu adalah salah satu dari dua baris kode yang harus saya miliki dalam mentransisikan aplikasi ke Python3.
Dave W. Smith
9

Anda tidak lulus nsendiri, melainkan range(n)[daftar bilangan bulat dari 0 hingga n-1 disertakan], dari tampilan Anda ke template Anda, dan yang terakhir Anda lakukan {% for i in therange %}(jika Anda benar-benar bersikeras berbasis 1 daripada yang normal 0 Indeks berbasis yang dapat Anda gunakan forloop.counterdalam tubuh loop ;-).

Alex Martelli
sumber
9

Hanya memetikan orang lain menemukan pertanyaan ini ... Saya telah membuat tag template yang memungkinkan Anda membuat range(...): http://www.djangosnippets.org/snippets/1926/

Menerima argumen yang sama dengan builtin 'range' dan membuat daftar yang berisi
hasil 'rentang'.

Sintaksis:
    {% mkrange [start,] stop [, step] sebagai context_name%}

Sebagai contoh:
    {% mkrange 5 10 2 sebagai some_range%}
    {% untuk saya di some_range%}
      {{i}}: Sesuatu yang ingin saya ulangi \ n
    {% endfor%}

Menghasilkan:
    5: Sesuatu yang ingin aku ulangi 
    7: Sesuatu yang ingin saya ulangi 
    9: Sesuatu yang ingin saya ulangi

David Wolever
sumber
1
-1 mendukung potongan Alex Pi yang menambahkan dukungan argumen variabel.
m000
9

Saya berusaha sangat keras pada pertanyaan ini, dan saya menemukan jawaban terbaik di sini: (dari cara loop 7 kali dalam template Django )

Anda bahkan dapat mengakses idx!

views.py:

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

html:

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

Anda dapat lulus:

{'n': range (n)}

Untuk menggunakan templat:

{% untuk i di n%} ... {% endfor%}

rkoots
sumber
mudah dibaca dan sederhana, mudah dimengerti apa yang terjadi jika Anda orang berikutnya yang menjaga kode
rossdavidh
7

Anda harus menggunakan " slice " pada template, contohnya seperti ini:

di views.py

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

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

di store_list.html:

<ul>
{% for store in ALL_STORES|slice:":10" %}
    <li class="store_item">{{ store.name }}</li>
{% endfor %}
</ul>
Vinta
sumber
1
Tidak yakin apakah ini yang dicari OP, tapi itulah tepatnya yang saya cari. =)
GChorn
7

Metode ini mendukung semua fungsi dari range([start,] stop[, step])fungsi standar

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

Pemakaian:

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

Keluaran

<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
sumber
solusi Anda tidak berfungsi for value in 0|range:"10,2". Anda harus mengubah kode Anda sebagai berikut:args = filter(lambda x: isinstance(x, int) and x >= 0, (_min, _max, _step))
Bedilbek
@Bedilbek kode ini meniru kisaran python standar. bahkan itu tidak mendukung rentang negatif tanpa parameter langkah eksplisit. >>> daftar (kisaran (10,2)) [] >>> daftar (kisaran (10,2, -1)) [10, 9, 8, 7, 6, 5, 4, 3]
Rebs
5

Saya hanya mengambil jawaban populer sedikit lebih jauh dan membuatnya lebih kuat. Ini memungkinkan Anda menentukan titik awal, jadi 0 atau 1 misalnya. Ini juga menggunakan fitur jangkauan python di mana ujungnya satu kurang sehingga dapat digunakan secara langsung dengan panjang daftar misalnya.

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

Kemudian dalam template Anda cukup sertakan file tag template di atas dan gunakan yang berikut ini:

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

Sekarang Anda dapat melakukan 1-6 alih-alih hanya 0-6 atau mengkodekannya dengan keras. Menambahkan langkah akan membutuhkan tag templat, ini harus mencakup lebih banyak kasus penggunaan jadi ini adalah langkah maju.

Paul Kenjora
sumber
Ini adalah perpanjangan dari jawaban @ guillermo-siliceo-trueba.
Paul Kenjora
5

Ini pada dasarnya membutuhkan suatu rangefungsi. Tiket fitur Django dinaikkan ( https://code.djangoproject.com/ticket/13088 ) untuk ini tetapi ditutup sebagai "tidak akan diperbaiki" dengan komentar berikut.

Kesan saya terhadap ide ini adalah bahwa ia mencoba mengarah ke pemrograman dalam template. Jika Anda memiliki daftar opsi yang perlu dirender, mereka harus dihitung dalam tampilan, bukan dalam template. Jika itu sesederhana rentang nilai, maka jadilah itu.

Mereka memiliki poin yang bagus - Template seharusnya merupakan representasi tampilan yang sangat sederhana. Anda harus membuat data yang diperlukan terbatas dalam tampilan dan meneruskan ke templat dalam konteks.

Alastair McCormack
sumber
6
Tampilan harus untuk data, template harus untuk presentasi. Tampilan seharusnya tidak memerlukan pengetahuan tentang isi templat, khususnya rentang. Alasan Django untuk mengabaikan permintaan fitur ini adalah sampah.
Rebs
3

Kamu bisa memakai: {% with ''|center: i as range %}

rkoots
sumber
1
Bisakah Anda memberikan contoh / penjelasan tentang cara kerjanya?
Rebs
1

Jika nomor tersebut berasal dari model, saya menemukan ini sebagai tambalan yang bagus untuk model:

def iterableQuantity(self):
    return range(self.quantity)
Alper
sumber
2
Tidak yakin mengapa Anda terpilih, itu adalah jawaban yang valid. Saya tidak suka solusi ini dibandingkan dengan menerapkan filter yang tepat seperti yang saya berikan di atas. Model DB harus tetap ramping. Tapi itu masih lebih baik daripada jawaban yang diterima mayoritas.
Rebs
Saya bahkan tidak tahu ...
Alper
Saya terlambat 9 tahun tapi saya membesarkan Anda fam, jangan khawatir tentang itu.
Sahil
1

Bagi mereka yang mencari jawaban sederhana, hanya perlu menampilkan sejumlah nilai, katakanlah 3 dari 100 posting misalnya cukup tambahkan {% for post in posts|slice:"3" %}dan putar secara normal dan hanya 3 posting yang akan ditambahkan.

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

{% endfor %}
Muhammad Abdullah
sumber
Sementara kode ini dapat menjawab pertanyaan, memberikan konteks tambahan tentang mengapa dan / atau bagaimana kode ini menjawab pertanyaan meningkatkan nilai jangka panjangnya.
xiawi