jinja2 recursive loop vs dictionary - python

I have the following dictionary:
{'a': {'b': {'c': {}}}}
And the following Jinja2 template:
{% for key in dictionary recursive %}
<li>{{ key }}
{% if dictionary[key] %}
<ul>{{ loop(dictionary[key]) }}</ul>
{% endif %}
</li>
{% endfor %}
But Jinja2 always output:
<ul>
<li>a</li>
<ul>
<li>b</li>
</ul>
</ul>
My understood is that using recursive, it would show me the "c" element too, but it only works for a depth of 2. Why is dictionary not changing to the dictionary[key] at every loop iteration ? The dictionary is always the original dictionary.

You're right, dictionary isn't being updated in the recursion calls, and the loop cannot continue because the keys aren't found.
A workaround to this problem is using just the variables assigned in the for loop. In the dictionary example, this means to iterate through the items of the dictionary instead of just the keys:
from jinja2 import Template
template = Template("""
{%- for key, value in dictionary.items() recursive %}
<li>{{ key }}
{%- if value %}
Recursive {{ key }}, {{value}}
<ul>{{ loop(value.items())}}</ul>
{%- endif %}
</li>
{%- endfor %}
""")
print template.render(dictionary={'a': {'b': {'c': {}}}})
The output of this script is:
<li>a
Recursive a, {'b': {'c': {}}}
<ul>
<li>b
Recursive b, {'c': {}}
<ul>
<li>c
</li></ul>
</li></ul>
</li>
where you can see that recursion on the b key works fine because both key and value are updated on each iteration of the loop (I added the "Recursive key, value" message to the template to make it clear).

try something like this:
{% for key in dictionary recursive %}
<li>{{ key }}
{% if dictionary[key] %}
<ul>{{ loop(dictionary[key].keys()) }}</ul>
{% endif %}
</li>
{% endfor %}
I think you need to pass an iterable into the loop() construct.

Related

Iterating through Python dictionary with Jinja2

I've scoured the internet and can't seem to find the solution that fits my case.
I have a dictionary:
{"1528430400000": 129, "1528516800000": 123.14, "1528603200000": 117.28, "1528689600000": 111.42, "1528776000000": 105.56, "1528862400000": 99.7, "1528948800000": 93.84, "1529035200000": 87.98, "1529121600000": 82.12, "1529208000000": 76.26, "1529294400000": 70.4, "1529380800000": 64.54, "1529467200000": 58.68, "1529553600000": 52.82, "1529640000000": 46.96, "1529726400000": 41.1, "1529812800000": 35.24, "1529899200000": 29.38, "1529985600000": 23.52, "1530072000000": 17.66, "1530158400000": 11.8, "1530244800000": 5.94, "1530331200000": 0.08, "1530417600000": 0}'
where each key is a javascript-formatted date.
I'm looking for a simple iteration through each key and value.
example:
{% for key,value in dict %}
{{key}}, {{value}}
{% endfor %}
Use:
{% for key, value in dict.items() %}
<h1>Key: {{key}}</h1>
<h2>Value: {{value}}</h2>
{% endfor %}
let's suppose your dictionary is "my_dict".
view.py (django) will have-
return render(request, 'template', { 'my_dict' :
my_dict })
HTML page will have-
{% for k,v in my_dict.items %}
{{ k }}: {{ v }} <br>
{% endfor %}
You can pass dict.items to the template rendering object:
return flask.render_template('template_name', data = the_dict.items())
Then, in the HTML:
{%for a, b in data%}
<span>Key: {{a}}, value: {{b}}</span>
{%endfor%}
{% if dict_var |type_debug == 'dict' %}
{% for key in dict_var %}
{{ key }}: "{{ dict_var[key] }}"
{% endfor %}
{% endif %}
use this will error: ValueError: too many values to unpack in sometimes
{% if dict_var |type_debug == 'dict' %}
{% for key, value in dict_var %}
{{ key }}: "{{ value }}"
{% endfor %}
{% endif %}

Django template and part of a dictionary of lists

in Django I want to display some entries in a dictionary of lists.
My context is:
keys = ['coins', 'colors']
dict = {'colors':['red', 'blue'],
'animals':['dog','cat','bird'],
'coins':['penny','nickel','dime','quarter'] }
Template code:
<ul>{% for k in keys %}
<li>{{ k }}, {{ dict.k|length }}: [{% for v in dict.k %} {{ v }}, {% endfor %}]
{% endfor %}</ul>
I want to see:
* coins,4: [penny, nickel, dime, quarter,]
* colors,2: [red, blue,]
But what I actually see is keys but no values:
* coins,0: []
* colors,0: []
Note: I also tried dict.{{k}} instead of dict.k, but as expected that just gave a parse error in template rendering. I'll get rid of the trailing comma with forloop.last after getting the basic list working.
What is the secret sauce for displaying selected values from a dictionary of lists?
The question django template and dictionary of lists displays an entire dictionary, but my requirement is to display only a few entries from a potentially very large dictionary.
The problem (as you suspected) is that dict.k is evaluated to dict['k'] where 'k' is not a valid key in the dictionary. Try instead to iterate each item pair using dict.items and only display the results for the keys you're concerned with:
<ul>{% for k, v in dict.items %}
{% if k in keys %}
<li>
{{ k }}, {{ v|length }}: [{% for val in v %} {{ val }},{% endfor %}]
</li>
{% endif %}
{% endfor %}
</ul>
<ul>
{% for k, v in dict.items %} # instead of iterating keys, iterate dict
{% if k in keys %} # if key found in keys
<li>
{{ k }}, {{ v|length }}: [{% for val in v %} {{ val }},{% endfor %}]
</li>
{% endif %}
{% endfor %}
</ul>

Django: templates and iterate over dict

I have a dict:
>>> some_dict
{1: ['String1', 'String2', 'String3','String4' ],
2: ['String1_2', 'String2_2', 'String3_2', 'String4_2' ],}
In my template i want to iterate over this dict and display values in html. So i sent this dict from view:
return render_to_response('tournament.html',
{.....
'some_dict' : some_dict,
'some_dict_range' : range(4),
.....
})
In tournament.html i trying to iterate over some_dict. I want to get output that should looks like:
'String1', 'String2', 'String3','String4'
{% for iter1 in some_dict_range%}
{{some_dict.0.iter1}}<br>{% endfor %}
And as result, i get nothing.
But when i trying to get same result without iterator:
some_dict.0.0, some_dict.0.1, etc. i get what i need ('String1', 'String2', 'String3','String4').
And when i trying to view values of "iter1" i get the right digits:
{% for iter1 in some_dict_range%}
{{iter1}}<br> {% endfor %}
0, 1, 2 ...
Why this doesn't work this way? And if i wrong in design of this, how it should looks like? I mean - what the right way to iterate over this dict and display values in html-template?
Shouldn't:
{{some_dict.0.iter1}}<br>{% endfor %}
Be:
{{some_dict.iter1.0}}<br>{% endfor %}
^^^^^^^
Else you're trying to access some_dict[0] which isn't present...
To avoid passing in the range (as I assume you're wanting to output the dict in key order), you can use the following:
{% for k, v in some_dict.items|sort %}
Position {{ k }} has a first value of {{ v.0 }} and has:<br>
{{ v|join:"<br/>" }}
{% for item in v %}
{{ item }}
{% endfor %}
{% endfor %}

how to iterate through dictionary in a dictionary in django template?

My dictionary looks like this(Dictionary within a dictionary):
{'0': {
'chosen_unit': <Unit: Kg>,
'cost': Decimal('10.0000'),
'unit__name_abbrev': u'G',
'supplier__supplier': u"Steve's Meat Locker",
'price': Decimal('5.00'),
'supplier__address': u'No\r\naddress here',
'chosen_unit_amount': u'2',
'city__name': u'Joburg, Central',
'supplier__phone_number': u'02299944444',
'supplier__website': None,
'supplier__price_list': u'',
'supplier__email': u'ss.sss#ssssss.com',
'unit__name': u'Gram',
'name': u'Rump Bone',
}}
Now I'm just trying to display the information on my template but I'm struggling. My code for the template looks like:
{% if landing_dict.ingredients %}
<hr>
{% for ingredient in landing_dict.ingredients %}
{{ ingredient }}
{% endfor %}
Print {{ landing_dict.recipe_name }}
{% else %}
Please search for an ingredient below
{% endif %}
It just shows me '0' on my template?
I also tried:
{% for ingredient in landing_dict.ingredients %}
{{ ingredient.cost }}
{% endfor %}
This doesn't even display a result.
I thought perhaps I need to iterate one level deeper so tried this:
{% if landing_dict.ingredients %}
<hr>
{% for ingredient in landing_dict.ingredients %}
{% for field in ingredient %}
{{ field }}
{% endfor %}
{% endfor %}
Print {{ landing_dict.recipe_name }}
{% else %}
Please search for an ingredient below
{% endif %}
But this doesn't display anything.
What am I doing wrong?
Lets say your data is -
data = {'a': [ [1, 2] ], 'b': [ [3, 4] ],'c':[ [5,6]] }
You can use the data.items() method to get the dictionary elements. Note, in django templates we do NOT put (). Also some users mentioned values[0] does not work, if that is the case then try values.items.
<table>
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
</tr>
{% for key, values in data.items %}
<tr>
<td>{{key}}</td>
{% for v in values[0] %}
<td>{{v}}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
Am pretty sure you can extend this logic to your specific dict.
To iterate over dict keys in a sorted order - First we sort in python then iterate & render in django template.
return render_to_response('some_page.html', {'data': sorted(data.items())})
In template file:
{% for key, value in data %}
<tr>
<td> Key: {{ key }} </td>
<td> Value: {{ value }} </td>
</tr>
{% endfor %}
This answer didn't work for me, but I found the answer myself. No one, however, has posted my question. I'm too lazy to
ask it and then answer it, so will just put it here.
This is for the following query:
data = Leaderboard.objects.filter(id=custom_user.id).values(
'value1',
'value2',
'value3')
In template:
{% for dictionary in data %}
{% for key, value in dictionary.items %}
<p>{{ key }} : {{ value }}</p>
{% endfor %}
{% endfor %}
If you pass a variable data (dictionary type) as context to a template, then you code should be:
{% for key, value in data.items %}
<p>{{ key }} : {{ value }}</p>
{% endfor %}
I am thankful for the above answers pointing me in the right direction. From them I made an example for myself to understand it better. I am hoping this example will help you see the double dictionary action more easily and also help when you have more complex data structures.
In the views.py:
bigd = {}
bigd['home'] = {'a': [1, 2] , 'b': [3, 4] ,'c': [5,6] }
bigd['work'] = {'e': [1, 2] , 'd': [3, 4] ,'f': [5,6] }
context['bigd'] = bigd
In the template.html:
{% for bigkey, bigvalue in bigd.items %}
<b>{{ bigkey }}</b> <br>
{% for key, value in bigvalue.items %}
key:{{ key }} <br>
----values: {{ value.0}}, {{value.1 }}<br>
{% endfor %}
<br>
{% endfor %}
Notice the list in the second dictionary is accessed by the index in the list.
Result in browser is something like:

Django view: How to display data from a dictionary

I've got a dictionary like {'a':{'c':2, 'd':4 }, 'b': {'c':'value', 'd': 3}}
How can I display this into a table in view?
Question is answered here:
In summary you access the code as you would for a python dictionary
data = {'a': [ [1, 2] ], 'b': [ [3, 4] ],'c':[ [5,6]] }
You can use the dict.items() method to get the dictionary elements:
<table>
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
</tr>
{% for key, values in data.items %}
<tr>
<td>{{key}}</td>
{% for v in values[0] %}
<td>{{v}}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
Depends on how you want to do it. In Django templates, you access keys the same way you access a method. That is, Python code like
print my_dict['a']['c'] # Outputs: 2
becomes
{{ my_dict.a.c }} {# Outputs: 2 #}
in Django templates.
Had a similar problem and I solved it this way
PYTHON
views.py
#I had a dictionary with the next structure
my_dict = {'a':{'k1':'v1'}, 'b':{'k2': 'v2'}, 'c':{'k3':'v3'}}
context = {'renderdict': my_dict}
return render(request, 'whatever.html', context)
HTML
{% for key, value in renderdict.items %}
<h1>{{ key }}</h1>
{% for k, v in value.items %}
<h1>{{ k }}</h1>
<h1 > {{ v }}</h1>
{% endfor %}
{% endfor %}
The outputs would be
{{ key }} = a
{{ k }} = k1
{{ v }} = v1 #and so forth through the loop.

Categories