Django template how to look up a dictionary value with a variable

191,532

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_ }}
Share:
191,532

Related videos on Youtube

Stan
Author by

Stan

Updated on July 12, 2022

Comments

  • Stan
    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
    Jeff over 11 years
    Django Custom Template Tag documentation, for those finding this in the future.
  • Berislav Lopac
    Berislav Lopac over 11 years
    Why is this not built in by default? :-(
  • Jorge Leitao
    Jorge Leitao almost 11 years
  • Evgeny
    Evgeny over 9 years
    in Jinja2 {{ mydict[key] }}
  • user
    user over 9 years
    Great solution. @BerislavLopac Sadly it's a wontfix with Django core developers : code.djangoproject.com/ticket/3371
  • AlanSE
    AlanSE almost 9 years
    Does the filter go in views.py, some extra filters.py, or what file?
  • Tom Maier
    Tom Maier over 8 years
    Is there a possibility to save the tag result in a variable?
  • staggart
    staggart over 8 years
    He 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
    DylanYoung over 7 years
    It 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
    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
    J0ANMM almost 7 years
    Note that this does not work if the dictionary you are trying to access contains another dictionary inside.
  • Paul Whipp
    Paul Whipp almost 7 years
    If 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
    MD. Khairul Basar over 6 years
    Why register = Library() ? What does it do ?
  • AmiNadimi
    AmiNadimi over 6 years
    If you want all your templates to know about your new filter, then you have to register it under django.template.base.Library class. by register = Library() we instantiate that class and use filter function annotator inside it to reach our need.
  • Andy
    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
    Keith Ritter almost 6 years
    I 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
    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
    Flimm almost 5 years
    The template code {{ dict_obj.obj.obj_name }} is in this case equivalent to Python code dict_obj["obj"]["obj_name"], however, the question is about the equivalent of dict_obj[obj][obj_name].
  • slajma
    slajma over 4 years
    I would still use return value.get(arg) because that would not throw a KeyError exception if the key is not present.
  • Jibin
    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
    Jibin over 3 years
    Is it possible to assign the value returned({{ mydict|lookup:item.name }}) to a variable
  • NJHJ
    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
    Martins over 3 years
    How is the answer used, inside a template?
  • weHe
    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
    François Fournier over 2 years
    return value.get(arg, None)
  • Jake Mulhern
    Jake Mulhern over 2 years
    This 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
    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
    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).