Home > OS >  How to make a for loop break on counter in Django Templates?
How to make a for loop break on counter in Django Templates?

Time:07-01

How can I make the for product in products loop break after the if condition is fulfilled 3 times. I have been trying to set up a counter but that isn't working... because set is not accepted inside of for loops. Though testing it out a bit more it isn't being accepted anywhere.

When I use set it throws this exception or a variation of it: Invalid block tag on line 11: 'set', expected 'endblock'. Did you forget to register or load this tag?

I am aware that I should put all the logic I'm using Templates for inside of the view and then pass it through the dictionary but it would take too much time to research everything about that and i just want to be done with this.

Honestly I am really tired it is 6am and idk what to do. Thank you for your help in advance. :)

Edit: I know I have to use namespace() for set to be able to propagate across scopes. But set itself is still raising the same exception as above.

Edit2: I thought that django uses jinja2 as it's templating language but it seems like that is not the case. I fixed the mentions of jinja2 as I haven't changed any of the defaults that come with a fresh install of django.

HTML

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

                    <div >
                        <h3 >{{product.name}}</h3>
                        <h3 >{{product.price}}</h3>
                    </div>
                </div>
            {% endif %}
        {% endfor %}  
        </div>
{% endfor %}

CodePudding user response:

You can't (by design).Django is opinionated by design, and the template language is intended for display and not for logic.

You can use Jinja instead.

Or, you can do the complicated stuff in Python and feed the results to the template language through the context. Bear in mind that appending arbitrary objects to a list in Python is a cheap operation. So (in a CBV) something like

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 you can't (easily?) implement break in Django templating, but you can easily give it the ability to count:

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

In the context pass context['counter'] = Counter()

In the template refer to {{counter.value}} as much as you want, and in a conditional where you want to count occurences, use {{counter.incr}}. But, it's hacky, and probably best avoided.

CodePudding user response:

The problem seems to arise due to a misconception of the templating functionality. It is to be used mainly for display purposes and not filtering purposes, and you are facing a filtering problem:

I want to filter the 3 first elements of a list that fulfill a specific condition

is your main issue and templating frameworks will be poor at solving your issue, whereas this is exactly what python and Django's ORM are good at.

Why don't you first filter in Django, then display in template? For example as follows:

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