How to use django template dot notation inside a for loop - python

I am trying to retrieve the value of a dictionary key and display that on the page in a Django template:
{% for dictkey in keys %}
<p> {{ mydict.dictkey }} </p>
{% endfor %}
(let's say 'keys' and 'mydict' have been passed into the template in the Context)
Django renders the page but without the dictionary contents ("Invalid template variable")
I assume the problem is that it is trying to do mydict['dictkey'] instead of mydict[actual key IN the variable dictkey]? How does one "escape" this behavior?
Thanks!
UPDATE:
Based on the answers received, I need to add that I'm actually looking specifically for how to achieve a key lookup inside a for loop. This is more representative of my actual code:
{% for key, value in mydict1.items %}
<p> {{ mydict2.key }} </p>
{% endfor %}
Basically, I have two dictionaries that share the same keys, so I can't do the items() trick for the second one.

See this answer to a (possibly duplicate) related question.
It creates a custom filter that, when applied to a dictionary with a key as it's argument, does the lookup on the dictionary using the key and returns the result.
Code:
#register.filter
def lookup(d, key):
if key not in d:
return None
return d[key]
Usage:
{% for dictkey in dict1.keys %}
<p> {{ dict2|lookup:dictkey }} </p>
{% endfor %}
Registering the filter is covered in the documentation.
I find it sad that this sort of thing isn't built in.

From http://docs.djangoproject.com/en/dev/ref/templates/builtins/#for
This can also be useful if you need to access the items in a dictionary. For example, if your context contained a dictionary data, the following would display the keys and values of the dictionary:
{% for key, value in data.items %}
{{ key }}: {{ value }}
{% endfor %}
The trick is that you need to call dict.items() to get the (key, value) pair.

See the docs: http://docs.djangoproject.com/en/dev/ref/templates/builtins/#for
{% for key, value in data.items %}
{{ key }}: {{ value }}
{% endfor %}

Related

How to access the dictionary keys and values in django templates

I have created a dictionary of message senders which is updating dynamically. If I print the dictionary keys in the python console window, I am getting the expected output but when I try to access the values in the Django template, I am getting nothing here is my python code;
views.py
def home(request):
senders = {}
chatting =Message.objects.filter(seen=False)
for msg in chatting:
user = User.objects.get(id=msg.sender.id)
if user != request.user and user not in senders.values():
senders.update({user.id : user})
return render(request, 'home.html', senders)
template Home.html
<div>
{% for key, val in senders %}
<div>
{{val}}
</div>
{% endfor %}
</div>
first of all,
are you sure you really need a dict here? usually Django has a list of dicts. So, you loop just list, like here: https://github.com/ansys/aedt-testing/blob/cefebb91675dd54391d6324cd78e7bc97d9a8f6b/aedttest/static/templates/project-report.html#L220
however,
answer to a direct question:
{% for key, value in data.items %}
{{ key }}: {{ value }}
{% endfor %}
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#for
use below instruction in template of django :
{{ key }}: {{ value }}

Looping through nested dictionary in Django template

My context dictionary for my Django template is something like the following:
{'key1':'1',
'key2':'2',
'key3':'3',
'key4':{'key5':{'key6':'6', 'key7':'7', 'key8':'8'}}}
I would like to iterate through the dictionary and print something like:
some label = 6
some label = 7
some label = 8
How can I achieve this in my Django template?
What's wrong with this ?
<ul>
{% for key, value in key4.key5.items %}
<li>{{ key }} : {{ value }}</li>
{% endfor %}
</ul>
NB: you didn't ask for looping over all keys in the context, just about accessing key4['key5'] content. if this wasn't wath you were asking for pleasit eadit your question to make it clearer ;-)
I am guessing you want to use a for loop in the django template to do this you must first pass the dictionary to the template in the views file like so make sure you add square brackets around the dictionary like this:
data = [{'key1':'1',
'key2':'2',
'key3':'3',
'key4':{'key5':{'key6':'6', 'key7':'7', 'key8':'8'}}
}]
return render(request,'name of template',{'data':data})
then in the html template:
{% for i in data%}
<p>{{i.key1}}</p>
<p>{{i.key2}}</p>
<p>{{i.key3}}</p>
<p>{{i.key4.key5.key6}}</p>
{% endfor %}
Now when you do the for loop you can access all the iteams in key4 like i have above when I put {{i.key4.key5.key6}}
Here is the docs for the for loop in django templates https://docs.djangoproject.com/en/3.0/ref/templates/builtins/
I am assuming thats what you want to do.
This has worked for me:
{% for key, value in context.items %}
{% ifequal key "key4" %}
{% for k, v in value.items %}
some label = {{ v.key6 }}
some label = {{ v.key7 }}
some label = {{ v.key8 }}
{% endfor %}
{% endif %}
{% endfor %}
If you want to print only what you have mentioned in question then it is possible but if we don't know the exact structure of dictionary then it is possible in django views not in django template.
You can't print value which is also a dictionary one by one in django template,
But you can do this in django view.
Check this post click here and do some changes in views.

.items not working on defaultdict in Django template

I can't get .items to work in my Django template:
copy and paste from my CBV's get_context_data:
context['data'] = assertion_dict
context['dataitems'] = assertion_dict.items()
return context
copy and paste from my template:
<h3>data dump</h3>
{{data}}
<h3>dataitems</h3>
{% for key, value in dataitems %}
{{ key }}: {{ value }} <br/>
{% endfor %}
<h3>data.items</h3>
{% for key, value in data.items %}
{{ key }}: {{ value }} <br/>
{% endfor %}
<h3>Not found test</h3>
{{ i_dont_exist }}
output:
**data dump**
defaultdict(<class 'list'>, {<BadgeType: Talent>: [<BadgeAssertion: Blender Blue Belt>], <BadgeType: Achievement>: [<BadgeAssertion: MyBadge#1>, <BadgeAssertion: MyBadge#1>, <BadgeAssertion: MyBadge#2>], <BadgeType: Award>: [<BadgeAssertion: Copy of Copy of Blenbade>]})
**dataitems**
Talent: [<BadgeAssertion: Blender Blue Belt>]
Achievement: [<BadgeAssertion: MyBadge#1>, <BadgeAssertion: MyBadge#1>, <BadgeAssertion: MyBadge#2>]
Award: [<BadgeAssertion: Copy of Copy of Blenbade>]
**data.items**
**Not found test**
DEBUG WARNING: undefined template variable [i_dont_exist] not found
Why isn't the second version working, where I use data.items in my template?
This is a known issue in Django: you cannot iterate over a defaultdict in a template. The docs suggest that the best way to handle this is to convert your defaultdict to a dict before passing it to the template:
context['data'] = dict(assertion_dict)
The reason it doesn't work, by the way, is that when you call {{ data.items }} in your template, Django will first attempt to find data['items'], and then data.items. The defaultdict will return a default value for the former, so Django will not attempt the latter, and you end up trying to loop over the default value instead of the dict.

Make a django template object iterable

I have a dictionary with a number of characteristics:
sort_options = SortedDict([
("importance" , ("Importance" , "warning-sign" , "importance")),
("effort" , ("Effort" , "wrench" , "effort")),
("time_estimate" , ("Time Estimate" , "time" , "time_estimate")),
])
I also have a list of actions as a query result. Each action has these attributes; In my template, I can call {{ action.effort }} or {{ action.time_estimate }} and get a result.
I'm iterating through my sort_options to populate twitter bootstrap icons:
{% for key, icon in sort_options.items %}
<i class="icon-{{ icon.1 }}"></i>
{% endfor %}
But I also want to display the action value for each of these attributed. Essentially, something like:
{% for key, icon in sort_options.items %}
<i class="icon-{{ icon.1 }}"></i>
{{ action.key }}
{% endfor %}
Where key would resolve to "importance" or "effort". I know this doesn't work. So I was trying to leverage the solution presented in this question.
The solution proposed a template filter:
def hash(h,key):
if key in h:
return h[key]
else:
return None
register.filter(hash)
{{ user|hash:item }}
Where the question used a dictionary that looked like so:
{'item1': 3, 'name': 'username', 'item2': 4}
I tried the following:
{% for key, icon in sort_options.items %}
<i class="icon-{{ icon.1 }}"></i>
{{ action|hash:key }}
{% endfor %}
But got an error:
Caught TypeError while rendering: argument of type 'Action' is not iterable
I believe this is because the template filter is getting just one attribute of the object (likely the name) as opposed to the whole dictionary:
[<Action: Action_one>, <Action: Task_two>...]
Is there a way to force the template to pass the full object to the template tag?
I think I finally get it. You want the equivalent of
getattr(action, key)
in your template. This answer describes the getattribute templatetag you'd need to do so.

How can I tell if a value is a string or a list in Django templates?

I've got a tuple of values I'm iterating in a Django template (1.4). Some of the values are strings which must just print out, others are tuples containing strings, which must be iterated themselves to print out their values. Is there a way, within the template, that I can decide if a given value, as I iterate over the master tuple, is a string or a list (tuple) ?
There's no builtin way to do so. A (somewhat dirty IMHO) workaround would be to implement a custom "is_string" filter, but the best solution would be to preprocess the values in the view to make it an uniform list of tuples (or list).
for the filter solution:
#register.filter
def is_string(val):
return isinstance(val, basestring)
and then in your templates:
<ul>
{% for whatever in something %}
<li>
{% if whatever|is_string %}
{{ whatever }}
{% else %}
<ul>
{{ whatever|unordered_list }}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
cf the excellent Django doc for more on custom filters and templatetags:
https://docs.djangoproject.com/en/stable/howto/custom-template-tags/
You can create an isinstance filter in the view or a helper module:
from django.template.defaultfilters import register
#register.filter(name="isinstance")
def isinstance_filter(val, instance_type):
return isinstance(val, eval(instance_type))
Then in the template you could do:
{% load isinstance %}
{% if some_value|isinstance:"list" %}
// iterate over list
{% else %}
// use string
{% endif %}

Categories

Resources