27

My view code looks basically like this:

context = Context() 
context['my_dict'] = {'a': 4, 'b': 8, 'c': 15, 'd': 16, 'e': 23, 'f': 42 }
context['my_list'] = ['d', 'f', 'e', 'b', 'c', 'a']

And what I'd like to do in my Django template is this:

<ul>
{% for item in my_list %} 
  <li>{{ item }} : {{ my_dict.item }}</li>
{% endfor %} 
</ul>

And I'd like this to output:

<ul> 
  <li> d : 16 </li> 
  <li> f : 42 </li> 
  <li> e : 23 </li> 
  <li> b : 8 </li> 
  <li> c : 15 </li> 
  <li> a : 4 </li> 
</ul> 

But the reference to the dict by variable name via {{ my_dict.item }} doesn't actually work. I suspect it's internally doing my_dict['item'] instead of my_dict[item]. Is there any way to work around this?

Vinod Kurup
  • 2,676
  • 1
  • 23
  • 18
slacy
  • 11,397
  • 8
  • 56
  • 61
  • Of course, I could always add more code in the view to say: context['my_derefernced'] = [ (v, context[my_dict][v]) for v in context['my_list'] ] but I'd rather not have to do that. The dicts can be quite large. – slacy Jan 14 '10 at 19:50
  • Look at this great solution: http://stackoverflow.com/questions/35948/django-templates-and-variable-attributes – fiatjaf Jan 01 '12 at 15:26
  • If the dicts are large, why not use generators? Maybe something like this: `context['my_dereferenced'] = ( (v, context[my_dict][v]) for v in context['my_list'] )` – user193130 Mar 20 '15 at 17:25

4 Answers4

16

There's no builtin way to do that, you'd need to write a simple template filter to do this: http://code.djangoproject.com/ticket/3371

Alex Gaynor
  • 14,353
  • 9
  • 63
  • 113
  • Thanks Alex. I knew I could write a template filter. Why not amend the template processor to include steps for {{ foo.bar }} to try foo.resolve_variable(bar, context) and foo[resolve_variable(bar,context)]? – slacy Jan 14 '10 at 19:56
  • 2
    @slacy If that feels unnatural and unwieldy to you, you might consider checking out Jinja. It's a bit more Pythonic and far less-opinionated than Django's built-in templating system. Not everyone agrees, but I personally like it better. – Joe Holloway Jan 11 '11 at 19:00
7

Try this to display the keys and values of the dictionary:

{% for key, value in your_dict.items %}
    {{ key }}: {{ value }}
{% endfor %}

https://docs.djangoproject.com/en/dev/ref/templates/builtins/#for

Shawn Chin
  • 84,080
  • 19
  • 162
  • 191
Alex Heretic
  • 281
  • 1
  • 3
  • 6
5

Here's a usage case of the suggested answer.

In this example, I created a generic template for outputting tabular data from a view. Meta data about the columns is held in context["columnMeta"].

Since this is a dictionary, i cannot rely on the keys to output the columns in order, so i have the keys in a separate list for this.

In my view.py:


c["columns"] = ["full_name","age"]
c["columnMeta"] = {"age":{},"full_name":{"label":"name"}}

In my templatetags file:


@register.filter
def getitem ( item, string ):
  return item.get(string,'')

In my template:

<tr>
<!-- iterate columns in order specified -->
{% for key in columns %}
<th>
 <span class="column-title">
    <!-- look label in meta dict.  If not found, use the column key -->
   {{columnMeta|getitem:key|getitem:"label"|default:key}}
  </span>
</th>
{% endfor %}</tr>
Dave
  • 1,196
  • 15
  • 22
2

For my needs, I wanted a single template filter that would work for dicts, lists, and tuples. So, here's what I use:

@register.filter
def get_item(container, key):
    if type(container) is dict:
        return container.get(key)
    elif type(container) in (list, tuple):
        return container[key] if len(container) > key else None
    return None
Cloud Artisans
  • 4,016
  • 3
  • 30
  • 37