Jinja2 change variable inside a loop - python

{% set foo = 200 %}
{% for item in items %}
{% set foo = 100 %}
{{ foo }}
{% endfor %}
{{foo}}
Output
100
200
foo outside of my Loop should be 100
how can i solve this issue?

Try also dictionary-based approach. It seems to be less ugly.
{% set vars = {'foo': False} %}
{% for item in items %} {% if vars.update({'foo': True}) %} {% endif %}
{% if vars.foo %} Ok(1)! {% endif %} {% endfor %}
{% if vars.foo %} Ok(2)! {% endif %}
This also renders:
Ok(1)!
Ok(2)!

Related

Jinja template groupby sorting issue

In this code block, I have grouped by headings. But I want to sort the titles in array index order. Not alphabetically.
{% set list = widget.attributes.faq_item %}
{% for title_group in list|groupby('value.main_title') %}
<h2 class="account-sss__title">{{title_group.grouper}}</h2>
{% for item in title_group.list %}
<a href="#" class="account-sss__list--link js-link">
{{item.value.question}}
</a>
<div class="account-sss__content js-account-sss__content">
{{item.value.answer}}
</div>
{% endfor %}
{% endfor %}
I solved the problem.
{% set list = widget.attributes.faq_item %}
{% set Arr_titles = [] %}
{% for event in list %}
{% if event.value.main_title not in Arr_titles %}
{% do Arr_titles.append(event.value.main_title) %}
{% endif %}
{% endfor %}
{% for index in Arr_titles %}
<h2 class="account-sss__title">{{index}}</h2>
{% for item in list %}
{% if index == item.value.main_title %}
<a href="#" class="account-sss__list--link js-link">
{{item.value.question}}
</a>
<div class="account-sss__content js-account-sss__content">
{{item.value.answer}}
</div>
{% endif %}
{% endfor %}
{% endfor %}

display list in django template

I have a list of tuples which looks something like the following:
answer_guess_list = [('A',), ('B', 'C',), ('A', 'B', 'C', 'D',)]
In my templates, I have a template variable with the same name.
{% for guess_list in answer_guess_list %}
<p>
{% for guess_value in guess_list %}
{{ guess_value }}, # Notice the comma (,)
{% endfor %}
</p>
{% empty %}
<p>Nothing to show.</p>
{% endfor %}
It displays the list as the following:
A,
B, C,
A, B, C, D,
I don't want the terminal commas and rather display it as:
A
B, C
A, B, C, D
I do not know how to achieve that.
Could you help please?
This would be one way to do it:
{% for guess_list in answer_guess_list %}
<p>
{% for guess_value in guess_list %}
{{ guess_value }}{% if forloop.counter < guess_list|length %}, {% endif %}
{% endfor %}
</p>
{% empty %}
<p>Nothing to show.</p>
{% endfor %}
Or you could also use the built-in template filter join:
{% for guess_list in answer_guess_list %}
<p>
{{ guess_list|join:", " }}
</p>
{% empty %}
<p>Nothing to show.</p>
{% endfor %}
Here is the documentation for the template tags, the below is the tag it self.
#register.filter(name="my_filter")
def fltr(tpl):
return ','.join([str(i) for i in tpl])
After registering this tag by following instructions at the docs, you can use it as:
<p>
{% for guess_value in guess_list %}
{{ guess_value|my_filter }},
{% endfor %}
</p>
There's a built-in option for this in for templatetag called foorloop.last. Simply change your code to this:
{% for guess_list in answer_guess_list %}
<p>
{% for guess_value in guess_list %}
{{ guess_value }}{% if not forloop.last %},{% endif %}
{% endfor %}
</p>
{% empty %}
<p>Nothing to show.</p>
{% endfor %}
and if for loop is last, trailing comma won't render.

How to choose or assign variable in django template?

I have an template:
{% if c == 2 %}
{% for time in a %}
code(1)
{% endfor %}
{% else %}
{% for time in b %}
repeat of code(1)
{% endfor %}
{% endif %}
As you can see this code has an repeating part. I want to refactor like this:
{% if c == 2 %}
var = a
{% else %}
var = b
{% endif %}
{% for time in var %}
code(1)
{% endfor %}
How to do this?
Don't do that in the template(and I don't think you can), do that in views.py instead:
var = c if c == 2 else b
# add to template context
context['var'] = var
If you add too much logic in template, people have to look at both places to figure out what's going on. But if you have all the logics in views.py it's clearer.

divide a categorized list into parts in django template

I have this model:
class Event_Category(models.Model):
event=models.ForeignKey(Event,related_name='event_category')
category=models.ForeignKey(Category,related_name='events')
user=models.ForeignKey(User)
in the view:
magazie_cats=Event_Category.objects.filter(event=instance).order_by('category').distinct()
return render_to_response('CompanyHub/Company/index.html', {'magazie_cats':magazie_cats},context_instance=RequestContext(request))
in the template:
{% regroup magazie_cats by category as service_list %}
I want to divide this categorized list into 3 parts and iterate over it. I tried to access each category by variable indexes:
{% for i in range(0,3) %}
{% for item in service_list.i.list %}
{{item.event.title}}
{% endfor %}
{% endfor %}
{% for i in range(3,6) %}
{% for item in service_list.i.list %}
{{item.event.title}}
{% endfor %}
{% endfor %}
{% for i in range(6,9) %}
{% for item in service_list.i.list %}
{{item.event.title}}
{% endfor %}
{% endfor %}
NOTE: the range for each loop is calculated by some custom filters based on service_list length . I didn't include the complete code to avoid complexity.
The problem is that the list variable index doesn't work and I don't know what to do.
You want to use the slice filter:
{% regroup magazie_cats by category as service_list %}
{% for cat in service_list|slice:":3" %}
{% for item in cat.list %}
{{item.event.title}}
{% endfor %}
{% endfor %}
{% for cat in service_list|slice:"3:6" %}
{% for item in cat.list %}
{{item.event.title}}
{% endfor %}
{% endfor %}
{% for cat in service_list|slice:"6:9" %}
{% for item in cat.list %}
{{item.event.title}}
{% endfor %}
{% endfor %}

How to increment a variable on a for loop in jinja template?

I would like to do something like:
variable p is from test.py which is a list ['a','b','c','d']
{% for i in p %}
{{variable++}}
{{variable}}
result output is:
1 2 3 4
You could use loop.index:
{% for i in p %}
{{ loop.index }}
{% endfor %}
Check the template designer documentation.
In more recent versions, due to scoping rules, the following would not work:
{% set count = 1 %}
{% for i in p %}
{{ count }}
{% set count = count + 1 %}
{% endfor %}
After 2.10, to solve the scope problem, you can do something like this:
{% set count = namespace(value=0) %}
{% for i in p %}
{{ count.value }}
{% set count.value = count.value + 1 %}
{% endfor %}
As Jeroen says there are scoping issues: if you set 'count' outside the loop, you can't modify it inside the loop.
You can defeat this behavior by using an object rather than a scalar for 'count':
{% set count = [1] %}
You can now manipulate count inside a forloop or even an %include%. Here's how I increment count (yes, it's kludgy but oh well):
{% if count.append(count.pop() + 1) %}{% endif %} {# increment count by 1 #}
Or...
{% set count = [] %}
{% for something-that-loops %}
{% set __ = count.append(1) %}
<div> Lorem ipsum meepzip dolor...
{{ count|length }}
</div>
{% endfor %}
(From comments by #eyettea and #PYB)
Here's my solution:
Put all the counters in a dictionary:
{% set counter = {
'counter1': 0,
'counter2': 0,
'etc': 0,
} %}
Define a macro to increment them easily:
{% macro increment(dct, key, inc=1)%}
{% if dct.update({key: dct[key] + inc}) %} {% endif %}
{% endmacro %}
Now, whenever you want to increment the 'counter1' counter, just do:
{{ increment(counter, 'counter1') }}
if anyone want to add a value inside loop then you can use this its working 100%
{% set ftotal= {'total': 0} %}
{%- for pe in payment_entry -%}
{% if ftotal.update({'total': ftotal.total + 5}) %}{% endif %}
{%- endfor -%}
{{ftotal.total}}
output = 5
Came searching for Django's way of doing this and found this post. Maybe someone else need the django solution who come here.
{% for item in item_list %}
{{ forloop.counter }} {# starting index 1 #}
{{ forloop.counter0 }} {# starting index 0 #}
{# do your stuff #}
{% endfor %}
Read more here:
https://docs.djangoproject.com/en/1.11/ref/templates/builtins/
I was struggle with this behavior too. I wanted to change div class in jinja based on counter. I was surprised that pythonic way did not work. Following code was reseting my counter on each iteration, so I had only red class.
{% if sloupec3: %}
{% set counter = 1 %}
{% for row in sloupec3: %}
{% if counter == 3 %}
{% set counter = 1 %}
{% endif %}
{% if counter == 1: %}
<div class="red"> some red div </div>
{% endif %}
{% if counter == 2: %}
<div class="gray"> some gray div </div>
{% endif %}
{% set counter = counter + 1 %}
{% endfor %}
{% endif %}
I used loop.index like this and it works:
{% if sloupec3: %}
{% for row in sloupec3: %}
{% if loop.index % 2 == 1: %}
<div class="red"> some red div </div>
{% endif %}
{% if loop.index % 2 == 0: %}
<div class="gray"> some gray div </div>
{% endif %}
{% endfor %}
{% endif %}
Just to shed more light into this problem.
Jinja2 variables behaves differently from that of conventional scripting languages, you can't modify the variable in a for loop.Hence to bypass this behaviour you can use a dictionary, since you can change the value of the dictionary.
**{% set margin={"margin_value":0} %}**
{% for lang in language %}
<ul>
<li style="margin-right: {{ margin.margin_value}}px">{{ lang }}</li>
</ul>
**{% if margin.update({"margin_value":margin.margin_value + 2}) %}
{% endif %}**
{% endfor %}
In the above code the value of the dictionary is being modified.

Categories

Resources