Django's dictsort template tag

26 October 2013 (updated 04 March 2015)

dictsort [1]
Takes a list of dictionaries and returns that list sorted by the key given in the argument. Eg: {{ value|dictsort:"name" }}

The documentation would let you to believe you can only sort dicts with it. What to do if you have a list of strings? After a bit of fumbling around it turns out that dictsort doesn't do a mere __getitem__ on each object but instead will take each object as a template context and evaluate the key as a variable, like {{ name }} would.

What does this mean? It means you can sort a list of strings by using the least changing method as the sort attribute. Remember that Django automatically calls any functions in templates. Example:

>>> from django.template import Template, Context
>>> print Template("""{% for i in items|dictsort:"lstrip" %}
...     {{ i }}
... {% endfor %}""").render(Context({
...     'items': ["x", "a", "c", "b"]
... }))

Of-course, this won't work very well if your strings start with spaces.

What else can you do? You can get in depth:

>>> print Template("""{% for i in items|dictsort:"a.b.c.d" %}
...     {{ i|safe }}
... {% endfor %}""").render(Context({
...     'items': [
...         {'a': {'b': {'c': {'d': "x"}}}},
...         {'a': {'b': {'c': {'d': "a"}}}},
...         {'a': {'b': {'c': {'d': "c"}}}},
...         {'a': {'b': {'c': {'d': "b"}}}},
...     ]
... }))
    {'a': {'b': {'c': {'d': 'a'}}}}
    {'a': {'b': {'c': {'d': 'b'}}}}
    {'a': {'b': {'c': {'d': 'c'}}}}
    {'a': {'b': {'c': {'d': 'x'}}}}

Wanted to sort by something in lowercase? Yep, you can do that too and you should always use lower as the last part in the key for strings. No one wants see stuff sorted by case:

>>> print Template("""{% for i in items|dictsort:"key.lower" %}
...     {{ i.key }}
... {% endfor %}""").render(Context({
...     'items': [
...         {'key': "X"},
...         {'key': "a"},
...         {'key': "c"},
...         {'key': "B"},
...     ]
... }))

This entry was tagged as django python