I'm trying to generate an HTML table with Jinja2. The data for the table is in an collections.OrderedDict where the keys are strings and the values are lists of strings.
I've tried to implement it using the following loops:
{% for key in table.keys() %}
{% for a_list in table[key] %}
{% for a_value in a_list %}
{{ a_value }}
{% endfor %}
{% endfor %}
{% endfor %}
Except in the Python console this works but in Jinja2 it dies with the error TypeError: 'int' object is not iterable
How do I iterate through a list in Jinja2?
You have one loop too many. table[key] is a list object, so looping over that gives you the values in the list:
{% for key in table.keys() %}
{% for a_value in table[key] %}
{{ a_value }}
{% endfor %}
{% endfor %}
Your extraneous loop tried to loop over the integer objects in your lists. Note that you don't need to loop over the keys() result; you can loop directly over the dictionary:
{% for key in table %}
{% for a_value in table[key] %}
{{ a_value }}
{% endfor %}
{% endfor %}
If you are not using the key in the loop, just loop directly over the values:
{% for list_value in table.values() %}
{% for a_value in list_value %}
{{ a_value }}
{% endfor %}
{% endfor %}
Related
I'm trying to display values from a dictionary within a dictionary in a template using django.
I have a dictionary like this in my views:
characters = {
"char1": {'name': "David",
'stars': 4,
'series': "All star"},
"char2": {'name': "Patrick",
'stars': 3,
'series': "Demi god"}
}
I can display the whole dictionary on the page, however I want to display only the 'name' and 'David' key:value pairs. I wrote the following in the template:
{% for char in characters %}
{% for key, value in char %}
{{ key }}: {{ value }}
{% endfor %}
{% endfor %}
However this doesn't show me anything. What is wrong with this double loop?
Thanks
You have to add .items when you loop through key value pairs.
See below (Python 3):
{% for char in characters.items %}
{% for c in char %}
name: {{ c.name }}
{% endfor %}
{% endfor %}
In Python 2 it would be .iteritems
{% for char in characters.iteritems %}
{% for c in char %}
name: {{ c.name }}
{% endfor %}
Thanks to kfarnell's help I finally managed to get this:
{% for character, params in characters.items %}
{{ params.name }}: {{ params.stars }}
{% endfor %}
I have a dictionary
>>> filterdata
{u'data': [{u'filter': u'predictions', u'filtervalue': u'32', u'filterlevel': u'cltv', u'filtertype': u'>'}, {u'filter': u'profile', u'filtervalue': u"'TOMMY'", u'filterlevel': u'firstname', u'filtertype': u'='}]}
and i am using this to in django template
{% for c in filterdata.data %}
{{c}} ## print the current iterating dictionay
{% for d in c.items %}
{{ d.filtervalue }} ## does not print anything
{% endfor %}
{% endfor %}
any idea what i am doing wrong
You're iterating too much. d is the set of key-value pairs in the dict; filteritems is one of those keys, not an attribute of the pairs themselves. Remove that inner loop.
{% for c in filterdata.data %}
{{ c.filtervalue }}
{% endfor %}
I'm passing a django template , an argument like :
{'dict' : {Object0:[object1, object2, object3,.....], Object1:[object4, object5], ... } }
Is there anyway to iterate through that dictionary inside the template ?
Something like this wouldn't work :
{% for obj in dict %}
{% for objs in dict.obj %}
{# do sth here ... #}
{% endfor %}
{% endfor %}
Thanks
In Python, iterating through a dict just iterates through its keys. You want the values:
{% for obj in dict.values %}
{% for item in obj %}
{{ item }}
{% endfor %}
{% endfor %}
If you need both keys and values, you could use items:
{% for key, value in dict.items %}
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 %}
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.