4

This seems silly, but I don't understand how Django Templates access nested data in Contexts. I can access the values of dictionaries nested in the context data structure with the . notation -- {{ aDictionary.i_am_a_key }} works fine. But if I try to iterate over a list of keys and get their value from that same dictionary, I get nothing. So

{% for key in keys_list %}{{ aDictionary.key }}{% endfor}}

just generates blanks.

What am I missing here? Does Django not support key access to context dictionaries on the fly? Do I need to write a custom tag to do this?

EDIT

My examples assume these data structures:

aDictionary = {'i_am_a_key': 'all good', 'i_am_another_key': 'okay'}
keys_list = ['i_am_a_key', 'i_am_another_key']
chernevik
  • 3,922
  • 9
  • 41
  • 55
  • Does `aDictionary` have keys like this `'i_am_a_key'` - i.e. is `i_am_a_key` the name of a variable that your template has access to, or a string literal? If it's a string literal, then that's your difference, since `key` is the name of a variable storing your key. – Dominic Rodger Dec 11 '09 at 21:41
  • Why are you iterating around the keys? What is preventing you from simply iterating over the dictionary itself? – brianz Dec 11 '09 at 22:34
  • Because I'd like to vary the keys for data retrieval without varying the data structure passed to the template. And it's easier for me to ensure that the proper values are retrieved by using a mapping structure, rather than ensuring that all values are stored in list or tuple in the proper order. – chernevik Dec 11 '09 at 22:42

3 Answers3

5

This is a fundamental limitation of the Django templating language.

Three solutions:

  1. Use {% for key,value in foo.items %} to get key and value.
  2. Use Jinja2 -- an almost Django-like templating system.
  3. User the expr djangosnippet to do the access math.
Peter Rowell
  • 17,605
  • 2
  • 49
  • 65
  • So the templating can't access the dictionary by key on-the-fly? I think Django's great, but I could wish that limitation were more clearly documented. – chernevik Dec 11 '09 at 21:55
  • 1
    Short answer: No. The explanation is that it is a deliberately restrictive programming language so that "template designers" don't ... something. Personally, I've never met a "template designer," just programmers who have to do the template programming because the actual designers can't handle nested includes, for loops, etc. It does tend to force you to keep business logic out of the templates. I recommend options 2 or 3 above. Jinja2 gives you all of Python, and the expr tag does much the same thing within Django's template tag framework. – Peter Rowell Dec 12 '09 at 02:05
  • Thanks. I'm probably going to go with brianz's approach -- select the data I need and put in an object, then pass that to the template, rather than try to select the data items in the template. I suppose it's kludgier, but should serve, and won't be that hard to read. – chernevik Dec 15 '09 at 19:29
3

It's not the same question, but the answer is similar to #844746.

You end up with a filter which you can do...

{% load getattribute %}
{% for key in keys_list %}
    {{ aDictionary|attr:key }}
{% endfor %}
Community
  • 1
  • 1
T. Stone
  • 19,209
  • 15
  • 69
  • 97
  • Saw that. I'd prefer to avoid writing a custom tag. – chernevik Dec 11 '09 at 21:51
  • 2
    Meh. If you're that averse to custom tags/filters, you'd better switch to Jinja. Writing custom tags and filters is how you make the Django template language fit your needs. – Carl Meyer Dec 13 '09 at 12:30
  • 1
    You're probably right, but I'm balancing "learn new tools / find most elegant solution" against "get stuff done". – chernevik Dec 15 '09 at 19:25
3

This is a different approach, but based on what you want to accomplish this is the angle I'd take.

If you want to keep a subset of some dictionary and you want to iterate around it's values in some ordered fashion, I'd copy the element you're interested in into a SortedDict (django/utils/datastructures.py).

In my mind, stuff like this should live in the view (all of this is untested):

sorted_dict = SortedDict()
for key in orig_dict:
    if interested(key):
        sorted_dict[key] = orig_dict[val]

and the templates should just be very dumb:

{% for key, val in sorted_dict.items %}{{ val }}{% endfor}}
brianz
  • 7,268
  • 4
  • 37
  • 44