3

I can't get .items to work in my Django template:

copy and paste from my CBV's get_context_data:

    context['data'] = assertion_dict
    context['dataitems'] = assertion_dict.items()

    return context

copy and paste from my template:

  <h3>data dump</h3>
  {{data}}

  <h3>dataitems</h3>
  {% for key, value in dataitems %}
     {{ key }}: {{ value }} <br/>
  {% endfor %}

  <h3>data.items</h3>
  {% for key, value in data.items %}
     {{ key }}: {{ value }} <br/>
  {% endfor %}

  <h3>Not found test</h3>
  {{ i_dont_exist }}

output:

**data dump**
defaultdict(<class 'list'>, {<BadgeType: Talent>: [<BadgeAssertion: Blender Blue Belt>], <BadgeType: Achievement>: [<BadgeAssertion: MyBadge#1>, <BadgeAssertion: MyBadge#1>, <BadgeAssertion: MyBadge#2>], <BadgeType: Award>: [<BadgeAssertion: Copy of Copy of Blenbade>]})

**dataitems**
Talent: [<BadgeAssertion: Blender Blue Belt>]
Achievement: [<BadgeAssertion: MyBadge#1>, <BadgeAssertion: MyBadge#1>, <BadgeAssertion: MyBadge#2>]
Award: [<BadgeAssertion: Copy of Copy of Blenbade>]

**data.items**

**Not found test**
DEBUG WARNING: undefined template variable [i_dont_exist] not found 

Why isn't the second version working, where I use data.items in my template?

43Tesseracts
  • 4,617
  • 8
  • 48
  • 94
  • There's nothing obviously wrong with your first example template. Check for typos or accidental reassignment of `context['data']` or deletion of items from `assertion_dict`. – Peter DeGlopper Sep 27 '15 at 23:33
  • To rule out typos and other problems, I sent both in the context at the same time, and copy/pasted the view, template, and resulting HTML output. Question is updated with this info. – 43Tesseracts Sep 28 '15 at 01:42
  • I would a) add a dump of `{{ data }}` somewhere in your template - Python dicts stringify in a reasonable way, and that should help verify whether or not your `data` variable contains what you expect - and b) temporarily set your `TEMPLATE_STRING_IF_INVALID` setting as described here: http://stackoverflow.com/a/8990344/2337736 – Peter DeGlopper Sep 28 '15 at 02:33
  • Added ``{{data}}`` dump – 43Tesseracts Sep 28 '15 at 02:39
  • Added string_if_invalid – 43Tesseracts Sep 28 '15 at 02:46

1 Answers1

9

This is a known issue in Django: you cannot iterate over a defaultdict in a template. The docs suggest that the best way to handle this is to convert your defaultdict to a dict before passing it to the template:

context['data'] = dict(assertion_dict)

The reason it doesn't work, by the way, is that when you call {{ data.items }} in your template, Django will first attempt to find data['items'], and then data.items. The defaultdict will return a default value for the former, so Django will not attempt the latter, and you end up trying to loop over the default value instead of the dict.

solarissmoke
  • 30,039
  • 14
  • 71
  • 73