.items not working on defaultdict in Django template - python

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.

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.

Modify django templates to check for values in a dict

I have the following Django template.
{% load custom_tags %}
<ul>
{% for key, value in value.items %}
<li> {{ key }}: {{ value }}</li>
{% endfor %}
I need to check for the value and do some modifications.
If the value is True , instead of value I have to print Applied , else if it False I need to print Not Applied.
How to achieve that?
Very simple if-else clause here. Take a look at the django template docs to familiarize yourself with some of the common tags.
{% if value %}
APPLIED
{% else %}
NOT APPLIED
{% endif %}
You asked how to do this as a filter... I'm not sure why, but here is it:
In your app's templatetags directory create a file called my_tags.py or something and make the contents
from django import template
register = template.Library()
#register.filter
def applied(value):
if value:
return 'Applied'
else:
return 'Not applied'
Then in your template make sure to have {% load my_tags %} and use the filter with {{ value|applied }}

Python/Django: Simple Django Template

Hi I am using App Engine/Python to do a simple website. I have some trouble with a Django template problem.
In short, I want to use a "ShortName" to access a "LongName".
The soource code:
LongName={"so":"stackoverflow","su":"superuser"}
ShortName=['so','su']
Then I pass these two parameters to the templates.
In the template I write:
{% for aname in ShortName %}
{{ aname }} stands for {{ LongName.aname }},
{% endfor %}
The output is:
so stands for, su stands for
No error is given. The LongName.aname wont work.
I have no idea whats wrong.
This is trying to access LongName['aname'], not LongName[aname].
You might have to write a custom template tag/filter to get this to work. This Django bug (marked WONTFIX) has a simple implementation:
def get(d, key):
return d.get(key, '')
register.filter(get)
which you would use by
{{ LongName|get:aname }}
after adding it to your app (that SO answer shows how to do it on GAE).
You could also pre-make a variable to loop over in the view, by passing in
# in view
name_abbrevs = [(k, LongName[k]) for k in ShortName]
# in template
{% for short_name, long_name in name_abbrevs %}
{{ short_name }} stands for {{ long_name }}
{% endif %}
If you really don't want to add a template tag -- which isn't that bad! you just make one file! :) -- or pass in an extra variable, Vic's approach will let you do this without touching the Python files at all. As he mentions, it involves a lot of pointless iteration, but it'll work fine for small lists.
Django templates have a drawback here. I've been in the same situation before. What you have to do is iterate over all the keys in LongName, and check if the key you're looking for matches the ShortName. Here you go:
{% for aname in ShortName %}
{% for short_version, long_version in LongName %}
{% if aname == short_version %}
{{ aname }} stands for {{ long_version }},
{% endif %}
{% endfor %}
{% endfor%}
It's inefficient, and essentially a pointless O(n^2) mechanism. However, there's no better way in pure Django templates to refer to entries of a dict by a variable name.

How to use django template dot notation inside a for loop

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

Categories

Resources