The problem with starting with a dictionary in Django templates

I am not sure why this template does not display anything on the page. Is there something obvious I'm 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 such type of model objects as:

 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 I only looked in the docs, I would see the answer. https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#for

However, this is a difficult situation, because the templates do not throw any errors at runtime when the loop cannot unpack the iterator elements.

+4
source share
3 answers

Edit

 {% for key, log in log_group %} 

to

 {% for key, log in log_group.items %} 
+5
source

Update the for loop to:

 {% for log in log_group.itervalues %} 

Or, if you really need key (your sample template does not show that you are using it):

 {% for key, log in log_group.iteritems %} 
+4
source

Also be very careful with defaultdicts in the django template, and I see in your code that you are really using defaultdict .

They obviously do not work properly inside the template due to the way django tries to access properties / attributes / etc. and the only solution is to convert them to dicts:

 context['dictstructure'] = dict(mydefaultdict) 

The documentation has been fixed after ticket # 16335 , changeet , to include a special notice on this issue.

Technically, when the template system encounters dot, it tries to execute the following searches in the following order:

  • Dictionary Search
  • Attribute Search
  • Method call
  • Index List Search

This can lead to unexpected behavior with objects that override dictionary searches. For example, consider the following code that tries to iterate over a collection.defaultdict file:

 {% for k, v in defaultdict.iteritems %} Do something with k and v here... {% endfor %} 

Because dictionary lookups occur first, this behavior fires and provides a default value instead of using the .iteritems () method. In this case, first consider converting to a dictionary.

Also see question Django template cannot execute defaultdict loop

+3
source

All Articles