Using a variable as dictionary key in Django templates

Posted on October 11, 2012

Introduction

So I ran into an interesting situation this weekend where I needed to use a variable as a dictionary key in a Django template. I had a dictionary and I wanted to iterate through it in order by key. Since the dictionary is an unordered data structure I created a list of the keys, sorted them, then iterated through the list using the iterator as the key for the dictionary.

d={"a":"apple", "b":"banana", "m":"mango", "e":"egg", "c":"carrot"}
ls = sorted(d)
print ls
for i in ls:
    print d[i]

Output:

['a','b','c','e','m']
'apple'
'banana'
'carrot'
'egg'
'mango'

Problem

This works great in python, but in django templates you can't use variables as a key for a dictionary. Here is an example of code in a template that DOESN'T WORK.

{% for i in ls %}
   {{ d.i }}
{% endfor %}

Solution

My solution was to come up with a custom template filter that allowed me to use the variable as a dictionary key. To create a template filter you first need to create a folder in your app called templatetags (don't forget the init.py). Then create a file where you will put your code. The name doesn't really matter but it will affect how we will import the template filter later so keep that in mind. I like the conventions _extras.py and named mine dictionary_extras.py

project/
        app/
             templatetags/
                 __init__.py
                 dictionary_extras.py

Next we need to write our template filter and register it to the template library. First we import the template module and create an instance of a template library so we can register our template filter.

from django import template
register = template.Library()

We then use a handy decorator to register our filter. If you use the name argument, you can give your filter a specific name, otherwise it will use the function name by default

@register.filter(name='access')
def access(value, arg):
    return value[arg]

There we go, we're all done. We can now use the access filter on a dictionary in templates as long as we load dictionary_extras. A full example below.

Example

dictionary_extras.py:

from django import template
register = template.Library()

@register.filter(name='access')
def access(value, arg):
    return value[arg]

views.py:

...
context["d"] = {"a":"apple", "b":"banana", "m":"mango", "e":"egg", "c":"carrot"}
context["ls"] = sorted(d)

return context

test.html:

{% load dictionary_extras %}

{% for key in ls %}
    {{ d|access:key }}
{% endfor %}