Django template how to look up a dictionary value with a variable
Solution 1
Write a custom template filter:
from django.template.defaulttags import register
...
@register.filter
def get_item(dictionary, key):
return dictionary.get(key)
(I use .get
so that if the key is absent, it returns none. If you do dictionary[key]
it will raise a KeyError
then.)
usage:
{{ mydict|get_item:item.NAME }}
Solution 2
Fetch both the key and the value from the dictionary in the loop:
{% for key, value in mydict.items %}
{{ value }}
{% endfor %}
I find this easier to read and it avoids the need for special coding. I usually need the key and the value inside the loop anyway.
Solution 3
You can't by default. The dot is the separator / trigger for attribute lookup / key lookup / slice.
Dots have a special meaning in template rendering. A dot in a variable name signifies a lookup. Specifically, when the template system encounters a dot in a variable name, it tries the following lookups, in this order:
- Dictionary lookup. Example: foo["bar"]
- Attribute lookup. Example: foo.bar
- List-index lookup. Example: foo[bar]
But you can make a filter which lets you pass in an argument:
https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-filters
@register.filter(name='lookup')
def lookup(value, arg):
return value[arg]
{{ mydict|lookup:item.name }}
Solution 4
For me creating a python file named template_filters.py
in my App with below content did the job
# coding=utf-8
from django.template.base import Library
register = Library()
@register.filter
def get_item(dictionary, key):
return dictionary.get(key)
usage is like what culebrón said :
{{ mydict|get_item:item.NAME }}
Solution 5
I had a similar situation. However I used a different solution.
In my model I create a property that does the dictionary lookup. In the template I then use the property.
In my model: -
@property
def state_(self):
""" Return the text of the state rather than an integer """
return self.STATE[self.state]
In my template: -
The state is: {{ item.state_ }}
Related videos on Youtube
Stan
Updated on July 12, 2022Comments
-
Stan almost 2 years
mydict = {"key1":"value1", "key2":"value2"}
The regular way to lookup a dictionary value in a Django template is
{{ mydict.key1 }}
,{{ mydict.key2 }}
. What if the key is a loop variable? ie:{% for item in list %} # where item has an attribute NAME {{ mydict.item.NAME }} # I want to look up mydict[item.NAME] {% endfor %}
mydict.item.NAME
fails. How to fix this? -
Jeff over 11 yearsDjango Custom Template Tag documentation, for those finding this in the future.
-
Berislav Lopac over 11 yearsWhy is this not built in by default? :-(
-
Jorge Leitao almost 11 yearsI think @Jeff meant Django Custom Template Filter documentation
-
Evgeny over 9 yearsin Jinja2 {{ mydict[key] }}
-
user over 9 yearsGreat solution. @BerislavLopac Sadly it's a wontfix with Django core developers : code.djangoproject.com/ticket/3371
-
AlanSE almost 9 yearsDoes the filter go in views.py, some extra filters.py, or what file?
-
Tom Maier over 8 yearsIs there a possibility to save the tag result in a variable?
-
staggart over 8 yearsHe did not ask to enumerate a dict (as you show) - he asked to get the dict's value given a variable key. Your proposal does not provide solution.
-
DylanYoung over 7 yearsIt is a solution (just very inefficient) since you can enumerate the items of the dict and then match with the key from the list.
-
Jorge Orpinel Pérez almost 7 years+alanse I added it as a sub-function INSIDE the views.py function in question... but see docs.djangoproject.com/en/1.10/howto/custom-template-tags/…
-
J0ANMM almost 7 yearsNote that this does not work if the dictionary you are trying to access contains another dictionary inside.
-
Paul Whipp almost 7 yearsIf your values are dicts, you can include another for loop to process their keys and values but is likely that the complexity is taking you towards it being worth using a custom filter as described in @culebron's answer.
-
MD. Khairul Basar over 6 yearsWhy
register = Library()
? What does it do ? -
AmiNadimi over 6 yearsIf you want all your templates to know about your new filter, then you have to register it under
django.template.base.Library
class. byregister = Library()
we instantiate that class and usefilter
function annotator inside it to reach our need. -
Andy almost 6 years@brunodesthuilliers I mean in terms of the conceptual design of JSX for rendering HTML content as compared to Django templates. There's no reason something much more React-like isn't possible in Python.
-
Keith Ritter almost 6 yearsI was only able to get this to work after adding a name argument based on @Yuji 'Tomita' Tomita answer: @register.filter(name='get_item')
-
Tobia over 5 years@BerislavLopac because the Django template language sucked when it was created and it still sucks today. Friends don't let friends use Django templates.
-
Flimm almost 5 yearsThe template code
{{ dict_obj.obj.obj_name }}
is in this case equivalent to Python codedict_obj["obj"]["obj_name"]
, however, the question is about the equivalent ofdict_obj[obj][obj_name]
. -
slajma over 4 yearsI would still use
return value.get(arg)
because that would not throw a KeyError exception if the key is not present. -
Jibin over 3 years@MatheusJardimB Is it possible to assign the return data of tag filter to a variable or to check the return data is not empty. like, variable={{ mydict|get_item:item.NAME }}
-
Jibin over 3 yearsIs it possible to assign the value returned({{ mydict|lookup:item.name }}) to a variable
-
NJHJ over 3 years@Jibin I am not sure what you mean by your question. Perhaps my code was confusing; I have corrected it and added comments since then.
-
Martins over 3 yearsHow is the answer used, inside a template?
-
weHe over 2 years@Jibin coming from grails/gsp and other template languages I had the same question - but one needs to think different in django: you can do that before you render the template. When you create the context for the template in the view you can just add transient properties and (I believe) even methods to your model objects and access those from the template - great for all adhoc stuff you need just in that template and gives very readable template code.
-
François Fournier over 2 yearsreturn value.get(arg, None)
-
Jake Mulhern over 2 yearsThis worked for me. How would I pass two arguments in this way? {{ mydict_get_item:'attribute', 'second_attribute' }} does not seem to work.
-
M.Mevlevi over 2 years@PaulWhipp i have the same problem but the key has multi values and when im tring your answer it shows only first value .
-
Paul Whipp over 2 years@M.Mevlevi I'm not sure what you mean by a key having multi values but I'm guessing that you have something like a dict with {a: [1, 2, 3]}. value would be bound to [1, 2, 3] in that case so you'd need to handle that appropriately rather than just presenting the value directly (which assumes it has a string representation).