How to iterate over nested dictionaries in django templates - django

I'm not sure the most efficient way to iterate over my nested dictionaries to print a matrix of the total and good values for every fruit for each date. Take for instance the two lists and dictionary below:
fruits = ['apples','oranges','bananas']
harvest_dates = ['2011-07-23','2011-07-22','2011-07-21']
harvest_data = {
'apples': {
'2011-07-23': {
'total': 100,
'good': 80},
'2011-07-22': {
'total': 97,
'good': 92},
'2011-07-21': {
'total': 90,
'good': 85}
},
'oranges': {
'2011-07-23': {
'total': 86,
'good': 82},
'2011-07-22': {
'total': 90,
'good': 75},
'2011-07-21': {
'total': 92,
'good': 92}
},
'bananas': {
'2011-07-23': {
'total': 10,
'good': 9},
'2011-07-22': {
'total': 12,
'good': 11},
'2011-07-21': {
'total': 9,
'good': 9}
}
}
I can easily do this in python:
for fruit in fruits:
for day in harvest_dates:
print "harvest: %s" % harvest_data[fruit][day]['total']
print "good crop: %s" % harvest_data[fruit][day]['good']
But I don't know how to access this data in django templates. I had been trying something such as:
{% for fruit in fruits %}
...
{% for day in harvest_dates %}
...
{{ harvest_data.fruit.day.total }}
{{ harvest_data.fruit.day.good }}
...
{% endfor %}
{% endfor %}
But it's simply not working.
{% for fruit in fruits %}
{{ harvest_data.fruit }} <--- this does not exist
{{ harvest_data[fruit] }} <--- this does not work
{% endfor %}
I'm a complete amateur and I'm probably going about this all wrong, but I've Google'd quite a bit and it's not clear to me what the best approach to getting the data I want is.

Since you're familiar with python, the following is logically how you would want to iterate through your dictionary in a Django template:
for key,value in harvest_data.items():
... print key
... for key2,value2 in value.items():
... print key2
... for key3,value3 in value2.items():
... print "%s:%s"%(key3,value3)
In your template, this translates as follows:
{% for key, value in harvest_data.items %}
{{ key }} <br>
{% for key2,value2 in value.items %}
{{ key2 }} <br>
{% for key3, value3 in value2.items %}
{{ key3 }}:{{ value3 }} <br>
{% endfor %}
{% endfor %}
{% endfor %}
The Django docs actually briefly include an example of how to iterate through dictionaries when describing how the for template tag works:
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#for

as rolling stone says thats the way to iterate over dictionaries in templates, i would only change the key, value keywords for different keywords in every iteration like this:
{% for key, value in harvest_data.items %}
{{ key }} <br>
{% for key2,value2 in value.items %}
{{ key2 }} <br>
{% for key3, value3 in value2.items %}
{{ key3 }}:{{ value3 }} <br>
{% endfor %}
{% endfor %}
{% endfor %}
just for the sake of clarity :)
And if you want to line up your values i would suggest you use another data structure where you can sort by date, for example a something like this:
{ 'oranges' : [(date1, value1), (date2,value2)] ...}
Try to do the least possible operations in your templates, so dont do a sort or nested if's if you dont have to

Really old question, but I will add my 1.5c.
This is a good use case of the regroup tag (https://docs.djangoproject.com/en/1.9/ref/templates/builtins/#regroup) and a bit of data refactoring:
Have your data as a simple list of data points:
harvest_data = [
{'fruits': 'apples', 'date': '2011-07-23', 'total': 100, 'good': 80},
# ...
]
In your template, group by the chosen dimension(s):
{% regroup harvest_data by fruits as data_by_fruits %}
{% for data in data_by_fruits %}
<h1>{{ data.grouper }}</h1> # 'apples'
{% regroup data.list by date as data_by_fruits_date %}
{% for data_1 in data_by_fruits_date %}
<h2>{{ data_1.grouper }}</h2> # '2011-07-23'
{% for datapoint in data_1.list %}
total: {{ datapoint.total }} <br/>
good: {{ datapoint.good }} <br/>
{% endfor %}
{% endfor %}
{% endfor %}

Related

How to display a multi layer JSON in Django template?

So I have this JSON response:
{
"orders": [
{
"orderId": "4123456789",
"dateTimeOrderPlaced": "2017-02-09T12:39:48+01:00",
"orderItems": [
{
"orderItemId": "2012345678",
"ean": "0000007740404",
"cancelRequest": false,
"quantity": 10
}
]
}
]
}
I passed it in my view with the .json() method. I use this in my template:
{% for key, value in orders.items %}
{{ key }}: {{ value }}
{% endfor %}
I get this in my HTML:
orders: [{'orderId': '2529081520', 'dateTimeOrderPlaced': '2019-09-07T00:12:16+02:00', 'orderItems': [{'orderItemId': '2298728074', 'ean': '8945005881389', 'cancelRequest': False, 'quantity': 1}]}]
But how to dissect it further? For example to get the OrderId or the ean?
You can access dictionary items with the template variable dot-notation, like this
{% for order in orders.orders %}
{{ order.orderId }}
{% for item in order.orderItems %}
{{ item.ean }}
{% endfor %}
{% endfor %}
Assuming the context variable orders contains your parsed JSON, this template would be rendered like this:
OrderId: 4123456789
EAN: 0000007740404

How to use the current index to get the value of another array?

I've read this, and I have an array like that:
context[u'erreurs'] = {
'aa': {'titres': [], 'liste': [], 'urls': []},
'bb': {'titres': [], 'liste': [], 'urls': []},
'...': {'titres': [], 'liste': [], 'urls': []}
}
If there's an error, 'titres', 'liste' and 'urls' become array of strings, filled with adequates values.
In my template, if erreur is set I do this:
{% for idx, tab in erreurs.items %}
<ul>
{% for e in tab.liste %}
{% if user.is_authenticated %}
<li>{{ e }}</li>
{% else %}
<li>{{ e }}</li>
{% endif %}
{% endfor %}
</ul>
{% endfor %}
I would like to use the current index to use the value that is in another array, here: tab.urls. It doesn't work and gives me the error:
Could not parse the remainder: '[forloop.counter0]' from 'tab.urls[forloop.counter0]'
How to solve this?
Unfortunately, Django's templates don't support such syntax. You should put together a custom template filter:
# yourapp/templatetags/yourapp_tags.py:
from django import template
register = template.Library()
#register.filter
def at_index(array, index):
return array[index]
and use it like:
{% load yourapp_tags %}
{{ tab.urls|at_index:forloop.counter0 }}
You need to make an actual model that represents the data then the task becomes trivial
class YourModel(object):
titre = ''
liste = ''
url = ''
context[u'erreurs'] = {
'aa': [], # List of model
}
{% for idx, tab in erreurs.items %}
<ul>
{% for model in tab %}
{{ model.titre }}
{{ model.liste }}
{{ model.url }}
{% endfor %}
</ul>
{% endfor %}

Django template: iterating through dictionary wont show values

I have dictionary in my django template. When i simply output it using {{ x.servicestate }} it will print its contents into html:
[{'efefefef': 'blad'}, {'efef': 'blad'}, {'eerer': 'blad'}, {'aaa': 'blad'}, {'b': 'blad'}, {'ererer': 'blad'}]
But when i use this to iterate:
{% for key,value in x.service_state %}
{{ key }}<br>{{ value }}
{% endfor %}
It will only output its keys:
efefefef
efef
eerer
aaa
b
ererer
What am i doing wrong?
You want iterate the dict, so you need to handle it. Try doing this:
For this list:
[{'efefefef': 'blad'}, {'efef': 'blad'}, {'eerer': 'blad'}, {'aaa': 'blad'}, {'b': 'blad'}, {'ererer': 'blad'}]
Let's call it blah
{% for b in blah %}
{% for k, v in b.items %}
{{ k }}, {{ v }} <br>
{% endfor %}
{% endfor %}

Django template: access inner dictionary

A newbie django template question, hope to get some pointers.
I'm passing back a dictionary to render to html for a page. The structure of the dictionary is like the following:
dic:{
"names":["name1", "name2", "name3"],
"names1":{
"addresses":["address1","address2","address3"],
"key2":[......]
......
}
"name2":{......}
}
How do I access the inner dictionaries? The only way to know the keys for those inner dictionaries is from the list, but I was unable to iterate through values pointed by key "names" and use that value as a key to get the other dictionary. I have looked into writing customer filters/tags but not sure exactly how to proceed.
Use items, from django docs:
{% for key, value in data.items %}
{{ key }}: {{ value }}
{% endfor %}
I tested it with your example:
In template:
<ul>
{% for l1_key, l1_value in dic.items %}
<li>{{ l1_key }}:
<ul>
{% for l2_key, l2_value in l1_value.items %}
<li>{{ l2_key }}: {{ l2_value }}</li>
{% empty %}
<li>{{ l1_value }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
This will output something like:
- name2:
- address: [1, 2, 3]
- names:
- ['name1', 'name2', 'name3']
- names1:
- key2: [1, 2]
- addresses: ['address1', 'address2', 'address3']
items return a list of tuples formed by (key, value)
I used this dic (fix minor problems in your example):
dic = {
"names":["name1", "name2", "name3"],
"names1":{
"addresses":["address1","address2","address3"],
"key2":[1,2]
},
"name2":{'address':[1,2,3]}
}

Django regroup of cursor results

Using Django, I have a fairly complex SQL query that is working fine and returning the results I want, so I am not keen to try to reproduce this using Django's model query notation.
I am passing my results to my template and am able to display them using the following notation:
{% for line in myresults %}
...
{{ line.0 }}
...
{{ line.1 }}
etc.
{% endfor %}
Is there any way to use the regroup tag on this result set?
If I try:
{% regroup myresults by myresults.0 as mylist %}
{% for item in mylist %}
{{ item.grouper }}
{% for line in item.list %}
...
{{ line.0 }}
{{ line.1 }}
etc.
I get all of the results as before (without any regrouping) but don't get the item.grouper (all I see is "None" as a single group rather than my multiple groups)
Is this a syntax issue or am I trying something that doesn't fit regroup's capabilities?
I have used regroup in the normal way with a list of objects, but the above has me stumped.
Any suggestions? Thanks in advance.
with {% regroup myresults by myresults.0 as mylist %} you group by the first item in the list myresults you must group by some field of the items.
Next example from here:
cities = [
{'name': 'Mumbai', 'population': '19,000,000', 'country': 'India'},
{'name': 'Calcutta', 'population': '15,000,000', 'country': 'India'},
{'name': 'New York', 'population': '20,000,000', 'country': 'USA'},
{'name': 'Chicago', 'population': '7,000,000', 'country': 'USA'},
{'name': 'Tokyo', 'population': '33,000,000', 'country': 'Japan'},
]
...and you'd like to display a hierarchical list that is ordered by country, like this:
India
Mumbai: 19,000,000
Calcutta: 15,000,000
USA
New York: 20,000,000
Chicago: 7,000,000
Japan
Tokyo: 33,000,000
You can use the {% regroup %} tag to group the list of cities by country. The following snippet of template code would accomplish this:
{% regroup cities by country as country_list %}
<ul>
{% for country in country_list %}
<li>{{ country.grouper }}
<ul>
{% for item in country.list %}
<li>{{ item.name }}: {{ item.population }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>