Loop through a defaultdict(list) structure in a django template - python

I have a structure my_dict like this:
defaultdict(<class 'list'>, {
<MyClass: myobject1>: [<ThingClass: mything1>, <ThingClass: mything2>, ...],
<MyClass: myobject2>: [<ThingClass: mything6>, <ThingClass: mything7>, ...],
<MyClass: myobject3>: [<ThingClass: mything45>, <ThingClass: mything46>, ...],
...
})
I want to loop through the objects something like this:
{% for object in my_dict %}
{{object.somefield}}
{% for thing in object %}
{{thing.somefield}}
{% endfor %}
{% endfor %}
How do I loop through the things in this nested loop? myobject1 is not iterable, so how do I get the iterable?

You should loop through .items() of the dictionary to get both object and the list in hand at each iteration:
{% for obj, things in my_dict.items %}
{{obj.somefield}}
{% for thing in things %}
{{thing.somefield}}
{% endfor %}
{% endfor %}

Related

How to tell list from non-list in Django template?

I've got a Django template I'd sometimes like to pass a list and sometimes like to pass a single value. How can the template tell which it was given?
I'm thinking the value would be set like one of these:
context = {
'foo' : 'bar
}
or:
context = {
'foo' : ['bar', 'bat', 'baz']
}
Then, the template would have code that looks something like this:
{% if foo isa list %}
{% for item in foo %}
{{ item }}<br>
{% endfor %}
{% else %}
{{ item}}<br>
{% endif %}
I can set it up to have foo or foolist, for example, and check for one or the other. However, it'd be a bit nicer (imo) to just have foo that was either a list or not.
If you intend to do it this way then just add a check that it doesn't have format(in case of string) method and has 0 index, if so then its a list else considered single value
{% if foo.0 and not foo.format %}
{% for item in foo %}
{{ item }}<br>
{% endfor %}
{% else %}
{{ item}}<br>
{% endif %}
I think your approach is needlessly complicated.
I would just go with a list:
views.py
foo_list = ['bar']
context = {
'foo': foo_list,
'foo_len': len(foo_list),
}
template
{% if foo_len == 1 %}
{{ foo.0 }}
{% else %}
{% for item in foo %}
{{ item }}
{% endfor %}
{% endif %}

Change List in Embedded For Loop in Django Template

I have the following code in my Django template:
{% for matrix_row in request.session.matrix_rows %}
{% for radio in form.matrix_row_one_column_value %}
<li>{{ radio }}</li>
{% endfor %}
{% endfor %}
How can I change the list for the inner for loop as the outer for loop is iterated over? For example, the lists for successive passes of the outer for loop should be as follows:
form.matrix_row_one_column_value
form.matrix_row_two_column_value
form.matrix_row_three_column_value
form.matrix_row_four_column_value
form.matrix_row_five_column_value
form.matrix_row_six_column_value
Any help would be appreciated. Thanks.
Why don't you do the work in the view instead of trying to come up with something complicated in the template?
For example, in your Python:
names = ['apple', 'orange', 'carrot']
colors = [ ['red', 'green'], ['orange', 'red'], ['orange', 'yellow'] ]
fruits = zip(names, colors)
And then in your template:
{% for name, colors in fruits %}
<div>
{{ name }} -
{% for color in colors %}
{{ color }}
{% endfor %}
</div>
{% endfor %}
If I understand you correctly, what you want to do is something like form[matrix_row]
{% for matrix_row in request.session.matrix_rows %}
{% for radio in form[matrix_row] %}
<li>{{ radio }}</li>
...
That isn't possible in Django templates, so you would need to add your own simple templatetag for that. Something like this
#register.filter
def keyvalue(dic, key):
"""Use a variable as a dictionary key"""
return dic[key]
And now you can do
{% for matrix_row in request.session.matrix_rows %}
{% for radio in form|keyvalue:matrix_row %}
<li>{{ radio }}</li>
...

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 %}

jinja2 recursive loop vs dictionary

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.

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:

Categories