Looping problem with dictionary in Django templates
I'm not sure why this template is not rendering anything to the page. Is there anything开发者_StackOverflow社区 obvious I am missing here?
View:
@user_passes_test(is_staff)
def details_activity_log(request, project_id, template='projects/details_activity_log.html'):
project = get_object_or_404(Project.objects.select_related(), pk=project_id)
action_log = project.projectactionlog_set.all()
log_group = defaultdict(list)
for log in action_log:
log_group[log.action_time.strftime('%y%m%d')].append(log)
#import pdb; pdb.set_trace()
return render_to_response(template, {
'log_group' : log_group,
'project' : project,
'action_log' : action_log,
'tab_5' : 'active',
}, context_instance=RequestContext(request))
log_group contains a dict of model objects like so:
defaultdict(<type 'list'>, {'110614': [<ProjectActionLog: ProjectActionLog object>, ...]})
Template:
{% for key, log in log_group %}
{% for action in log %}
{{ action }}
{{ action.action_time }}
{{ action.user.first_name }}
{{ action.message }}
{{ action.object_name }}
{% endfor %}
{% endfor %}
Edit If only I had looked in the docs I would have seen the answer. https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#for
However it's a tricky situation since the templates don't throw any runtime errors when the loop can't unpack the iterator items.
Change
{% for key, log in log_group %}
to
{% for key, log in log_group.items %}
Update your for loop to:
{% for log in log_group.itervalues %}
Or, if you actually need key
(your example template doesn't show you using it):
{% for key, log in log_group.iteritems %}
Also be very careful with defaultdicts
in a django template, and I see in your code that you are indeed using a defaultdict
.
They plainly don't work as expected inside a template because of the way django attempts to access properties/attributes/etc. and the only solution is to convert them to dicts:
context['dictstructure'] = dict(mydefaultdict)
The template documentation was patched following ticket #16335, changeset to include a special notice on this issue.
Technically, when the template system encounters a dot, it tries the following lookups, in this order:
- Dictionary lookup
- Attribute lookup
- Method call
- List-index lookup
This can cause some unexpected behavior with objects that override dictionary lookup. For example, consider the following code snippet that attempts to loop over a collections.defaultdict:
{% for k, v in defaultdict.iteritems %} Do something with k and v here... {% endfor %}
Because dictionary lookup happens first, that behavior kicks in and provides a default value instead of using the intended .iteritems() method. In this case, consider converting to a dictionary first.
Please also see question Django template can't loop defaultdict
精彩评论