Как сделать так, чтобы цикл for прерывался по счетчику в jinja2?

Как сделать так, чтобы цикл for product in products прерывался после того, как условие if выполнится 3 раза. Я пытался установить счетчик, но это не работает... потому что set не принимается внутри циклов for. Хотя я проверил его еще немного, он не принимается нигде.

Когда я использую set, он выбрасывает это исключение или его разновидность: Invalid block tag on line 11: 'set', expected 'endblock'. Did you forget to register or load this tag?

Я знаю, что я должен поместить всю логику, для которой я использую jinja2, внутрь представления и затем передать ее через словарь, но это займет слишком много времени, чтобы исследовать все об этом, а я просто хочу закончить с этим.

Честно говоря, я очень устал, сейчас 6 утра, и я не знаю, что делать. Заранее спасибо за помощь. :)

Edit: Я знаю, что должен использовать namespace() для того, чтобы set мог распространяться по диапазонам. Но само set по-прежнему вызывает то же исключение, что и выше.

HTML

{% for category in categories %}
    <div>
        <h5 class="text-line"><a href="" class="store-category"><span>{{category.name}}</span></a></h5>
    </div>
        <!-- Cards Container -->
        <div class="shop-cards">
        {% set counter = 0 %}
        {% for product in products %}
            {% if product.category.categoryID == category.categoryID %}
                <!-- CARD 1 -->
                <div class="card">
                    <image class="product-image" src="{% static 'images/product-4.png' %}"></image>

                    <div class="card-category-price">
                        <h3 class="product-name">{{product.name}}</h3>
                        <h3 class="product-price">{{product.price}}</h3>
                    </div>
                </div>
            {% endif %}
        {% endfor %}  
        </div>
{% endfor %}

Проблема, по-видимому, возникает из-за неправильного понимания функциональности шаблонов. Она должна использоваться в основном для отображения, а не для фильтрации, а вы столкнулись с проблемой фильтрации:

Я хочу отфильтровать 3 первых элемента списка, которые удовлетворяют определенному условию

это ваша основная проблема, и шаблонизаторы будут плохо решать ее, в то время как это именно то, с чем хорошо справляются Python и ORM Django.

Почему бы вам сначала не отфильтровать в Django, а затем отобразить в шаблоне? Например, следующим образом:

...
products = queryset.filter(abc=condition)[:3]
context = Context({ 'products': products }) 
return HttpResponse(template.render(context))

Вы не можете (по дизайну). Django по дизайну ориентирован на мнения, а язык шаблонов предназначен для отображения, а не для логики.

Вместо этого вы можете использовать Jinja.

Или вы можете делать сложные вещи в Python и передавать результаты в язык шаблонов через контекст. Имейте в виду, что добавление произвольных объектов в список в Python - дешевая операция. Поэтому (в CBV) что-то вроде

context['first_three'] = self.get_first_three( whatever)
...

def get_first_three(self, whatever):
    first_three = []

    for obj in  ...:
        if complicated stuff ...
            first_three.append( obj)
            if len(first_three) == 3:
                break

     return first_three

BTW вы не можете (легко?) реализовать break в шаблонизаторе Django, но вы можете легко дать ему возможность считать:

class Counter( object):
    def __init__(self):
       self.n = 0
    def value(self):
       return self.n
    def incr(self):
       self.n += 1
       return ''

В контексте передают context['counter'] = Counter()

В шаблоне ссылайтесь на {{counter.value}} сколько угодно, а в условных выражениях, где нужно подсчитать случаи, используйте {{counter.incr}}. Но это халтура, и, вероятно, ее лучше избегать.

Вернуться на верх