Số vòng lặp trong các mẫu Django


261

Làm cách nào để viết một forvòng lặp số trong mẫu Django? Ý tôi là

for i = 1 to n

Câu trả lời:


392

Tôi đã sử dụng một kỹ thuật đơn giản hoạt động độc đáo cho các trường hợp nhỏ không có thẻ đặc biệt và không có ngữ cảnh bổ sung. Đôi khi điều này có ích

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

9
FWIW, 012 == 12, vì vậy nó sẽ chỉ lặp lại trên 1 và 2.
jason

22
{% cho tôi trong '0123456789' | make_list%} để lặp lại trên tất cả 10, không bỏ qua 0.
Rick

7
Tạo một chuỗi độ dài tùy ý với 'rjust'{% for i in "x"|rjust:"100" %}
Aaron

27
Lần thứ 3, câu trả lời này là BAD . KHÔNG sử dụng cái này. Sử dụng một thẻ mẫu và làm điều đó đúng. Tôi không thấy cách nói một câu trả lời là xấu, là lý do đủ để xóa một bình luận.
Hoàn trả

6
@Rebs Điều gì là xấu với điều này? Chắc chắn đó là hacky, nhưng thêm một thẻ mẫu chỉ vì bạn cần lặp lại một phạm vi nhỏ trong một dự án cũng không phải là một giải pháp tuyệt vời.
tobltobs

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

9
Câu trả lời chính xác. Hoạt động vì trung tâm tạo ra một chuỗi n không gian được lặp lại. Mỗi char không gian sau đó được bỏ qua, nhưng giá trị hiện tại trong phạm vi có thể được tìm thấy từ forloop.corer (hoặc forloop.corer0). Xem docs.djangoproject.com/en/dev/ref/temsheet/builtins/#center
chuyển vào

2
Câu trả lời chính xác! Không phải tạo bộ lọc mới.
Miguel Ike

Không cần phải làm bất cứ điều gì trong xem. Tuyệt vời hack
Mohammed Shareef C

106

Thật không may, điều đó không được hỗ trợ trong ngôn ngữ mẫu Django. Có một cặp vợ chồng của lời đề nghị , nhưng họ dường như một chút phức tạp. Tôi sẽ chỉ đặt một biến trong bối cảnh:

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

và trong mẫu:

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

13
Các động lực mà các tác giả Django đã không cho phép con trăn đơn giản trong các mẫu dường như vô nghĩa và không quan trọng so với nỗi đau và mất thời gian liên quan đến việc không có nó, chưa kể đến việc cần phải phát minh ra một ngôn ngữ hoàn toàn mới khi một con trăn hoàn toàn tuyệt vời (con trăn! ) đã ở ngay đó!
Bogatyr

2
@Bogatyr Nếu đó là những gì bạn muốn, chỉ cần sử dụng Jinja2: docs.djangoproject.com/en/1.9/topics/tem mẫu / Lỗi
tghw 11/2/2016

78

Tôi nghĩ về vấn đề này, tôi nghĩ là tốt nhất. Tôi giữ một my_filters.py trên thư mục templatetags.

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

Và bạn sẽ sử dụng như thế này:

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

1
Tôi nghĩ rằng đây là giải pháp đúng. Làm range(1, 16)để có được số bắt đầu từ 1, không phải 0.
chhantyal

Đồng thời tạo một tệp trống _ init _.py trong thư mục templatetags. Đồng thời thêm các dòng này vào đầu my_filters.py from django.template import Library;register = Library()
Ajeeb.KP

Thêm một tham số bộ lọc thứ hai và bạn có được chức năng phạm vi đầy đủ được tích hợp trong python. @register.filter(name='range') def filter_range(start, end): return range(start, end)Sau đó được sử dụng như {% for i in 1|range:6 %}{% endfor %}. Xem câu trả lời đầy đủ bên dưới ....
Paul Kenjora

Tôi đã thay đổi điều này một chút (định dạng xin lỗi) : try: return range(number) except: return []. Bằng cách đó, nó không bao giờ phát sinh lỗi và trả về một mảng trống (tương tự như cách mà hầu hết các hàm mẫu hoạt động).
Tim Tonomall


41

Bạn có thể vượt qua một ràng buộc của

{'n' : range(n) }

vào mẫu, sau đó làm

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

Lưu ý rằng bạn sẽ có hành vi dựa trên 0 (0, 1, ... n-1).

(Cập nhật cho khả năng tương thích Python3)


1
Sử dụng range(n)trong python 3, nếu tôi nhớ chính xác, xrange không được dùng nữa
Felício

Quả thực là có. Và đó là một trong hai dòng mã tôi phải có cơ hội chuyển đổi một ứng dụng sang Python3.
Dave W. Smith

9

Bạn không vượt qua nchính nó, nhưng thay vào đó range(n)[danh sách các số nguyên từ 0 đến n-1], từ chế độ xem của bạn đến mẫu của bạn và sau này bạn làm {% for i in therange %}(nếu bạn hoàn toàn nhấn mạnh vào 1 dựa trên thay vì 0 thông thường chỉ số dựa trên bạn có thể sử dụng forloop.countertrong cơ thể của vòng lặp ;-).


9

Chỉ cần bất cứ ai khác gặp phải câu hỏi này, tôi đã tạo một thẻ mẫu cho phép bạn tạo một range(...): http://www.djangosnippets.org/snippets/1926/

Chấp nhận các đối số tương tự như nội dung 'phạm vi' và tạo một danh sách chứa
kết quả của 'phạm vi'.

Cú pháp:
    {% mkrange [bắt đầu,] dừng [, bước] dưới dạng bối cảnh%}

Ví dụ:
    {% mkrange 5 10 2 dưới dạng some_range%}
    {% cho tôi trong some_range%}
      {{i}}: Một cái gì đó tôi muốn lặp lại \ n
    {% kết thúc%}

Sản xuất:
    5: Một cái gì đó tôi muốn lặp lại 
    7: Một cái gì đó tôi muốn lặp lại 
    9: Một cái gì đó tôi muốn lặp lại


1
-1 ủng hộ đoạn trích của Alex Pi có thêm hỗ trợ cho các đối số biến.
m000

9

Tôi đã rất cố gắng cho câu hỏi này và tôi tìm thấy câu trả lời tốt nhất ở đây: (từ cách lặp 7 lần trong các mẫu django )

Bạn thậm chí có thể truy cập idx!

lượt xem:

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

html:

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

9

Bạn có thể vượt qua :

{'n': phạm vi (n)}

Để sử dụng mẫu:

{% cho tôi trong n%} ... {% endfor%}


dễ đọc và đơn giản, dễ hiểu những gì đang xảy ra nếu bạn là người tiếp theo duy trì mã
rossdavidh

7

Bạn nên sử dụng " lát " trong mẫu, một ví dụ như thế này:

trong lượt xem

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

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

trong store_list.html:

<ul>
{% for store in ALL_STORES|slice:":10" %}
    <li class="store_item">{{ store.name }}</li>
{% endfor %}
</ul>

1
Không chắc đây có phải là thứ mà OP đang tìm kiếm hay không, nhưng đó chính xác là thứ tôi đang tìm kiếm. =)
GChorn

7

Phương pháp này hỗ trợ tất cả các chức năng của range([start,] stop[, step])chức năng tiêu chuẩn

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

Sử dụng:

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

Đầu ra

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

giải pháp của bạn không hoạt động for value in 0|range:"10,2". Bạn phải thay đổi mã của mình như sau:args = filter(lambda x: isinstance(x, int) and x >= 0, (_min, _max, _step))
Bedilbek

@Bedilbek mã này bắt chước phạm vi python tiêu chuẩn. thậm chí nó không hỗ trợ các phạm vi phủ định mà không có tham số bước rõ ràng. >>> danh sách (phạm vi (10,2)) [] >>> danh sách (phạm vi (10,2, -1)) [10, 9, 8, 7, 6, 5, 4, 3]
Hoàn trả

5

Tôi chỉ lấy câu trả lời phổ biến hơn một chút và làm cho nó mạnh mẽ hơn. Điều này cho phép bạn chỉ định bất kỳ điểm bắt đầu, vì vậy 0 hoặc 1 chẳng hạn. Nó cũng sử dụng tính năng phạm vi của python trong đó phần cuối là một ít hơn để nó có thể được sử dụng trực tiếp với độ dài danh sách chẳng hạn.

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

Sau đó, trong mẫu của bạn chỉ cần bao gồm tệp thẻ mẫu ở trên và sử dụng như sau:

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

Bây giờ bạn có thể làm 1-6 thay vì chỉ 0-6 hoặc mã hóa cứng. Thêm một bước sẽ yêu cầu thẻ mẫu, điều này sẽ bao gồm nhiều trường hợp sử dụng hơn vì vậy đó là một bước tiến.


Đây là phần mở rộng của câu trả lời @ guillermo-siliceo-trueba.
Paul Kenjora

5

Điều này về cơ bản đòi hỏi một rangechức năng. Một vé tính năng Django đã được nâng lên ( https://code.djangoproject.com/ticket/13088 ) cho điều này nhưng đóng lại là "sẽ không sửa chữa" với nhận xét sau.

Ấn tượng của tôi về ý tưởng này là nó đang cố gắng dẫn đến lập trình trong mẫu. Nếu bạn có một danh sách các tùy chọn cần được hiển thị, chúng sẽ được tính toán trong dạng xem, không phải trong mẫu. Nếu điều đó đơn giản như một loạt các giá trị, thì nó cũng vậy.

Họ có một điểm tốt - Mẫu được cho là đại diện rất đơn giản của chế độ xem. Bạn nên tạo dữ liệu yêu cầu hạn chế trong chế độ xem và chuyển đến mẫu trong ngữ cảnh.


6
Chế độ xem nên dành cho dữ liệu, mẫu nên được trình bày. Chế độ xem không yêu cầu kiến ​​thức về nội dung của mẫu, phạm vi cụ thể. Lý do của Django để bỏ qua các yêu cầu tính năng này là rác rưởi.
Hoàn trả

3

Bạn có thể dùng: {% with ''|center: i as range %}


1
Bạn có thể cung cấp một ví dụ / giải thích về cách thức này hoạt động?
Trả lại

1

Đối với những người đang tìm kiếm câu trả lời đơn giản, chỉ cần hiển thị một lượng giá trị, giả sử 3 từ 100 bài viết, ví dụ chỉ cần thêm {% for post in posts|slice:"3" %}và lặp nó bình thường và chỉ có 3 bài đăng sẽ được thêm vào.


0

Nếu số đến từ một mô hình, tôi thấy đây là một bản vá đẹp cho mô hình:

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

2
Không chắc chắn tại sao bạn đang bỏ phiếu, đó là một câu trả lời hợp lệ. Tôi không thích giải pháp này so với việc triển khai bộ lọc phù hợp như tôi đã cung cấp ở trên. Các mô hình DB nên được giữ nạc. Nhưng nó vẫn tốt hơn câu trả lời được chấp nhận đa số.
Trả lại

Tôi thậm chí không biết
Alper

Tôi đã 9 năm quá muộn nhưng tôi đã ủng hộ bạn nổi tiếng, thậm chí không lo lắng về điều đó.
Sahil

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

{% endfor %}

Mặc dù mã này có thể trả lời câu hỏi, cung cấp ngữ cảnh bổ sung về lý do và / hoặc cách mã này trả lời câu hỏi cải thiện giá trị lâu dài của nó.
xiawi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.