2011-01-21 11 views
59
import collections 

data = [ 
    {'firstname': 'John', 'lastname': 'Smith'}, 
    {'firstname': 'Samantha', 'lastname': 'Smith'}, 
    {'firstname': 'shawn', 'lastname': 'Spencer'}, 
] 

new_data = collections.defaultdict(list) 

for d in data: 
    new_data[d['lastname']].append(d['firstname']) 

print new_data 

Aquí está la salida:plantillas de Django no puede bucle defaultdict

defaultdict(<type 'list'>, {'Smith': ['John', 'Samantha'], 'Spencer': ['shawn']}) 

y aquí está la plantilla:

{% for lastname, firstname in data.items %} 
    <h1> {{ lastname }} </h1> 
    <p> {{ firstname|join:", " }} </p> 
{% endfor %} 

Pero el bucle en mi plantilla no funciona. Nada aparece. Ni siquiera me da un error. ¿Cómo puedo arreglar esto? Se supone que debe mostrar el apellido junto con el primer nombre, algo como esto:

<h1> Smith </h1> 
<p> John, Samantha </p> 

<h1> Spencer </h1> 
<p> shawn </p> 
+0

No ha mostrado el código que coloca el diccionario en el contexto de la plantilla. ¿Estás seguro de que está sucediendo correctamente? –

+0

Sí, todo lo demás se representa correctamente fuera del ciclo. – user216171

Respuesta

36

intento:

dict(new_data) 

y en Python 2 es mejor utilizar iteritems en lugar de items :)

+2

No puedo creer que algo tan simple como eso funcionó. ¡Muchas gracias! – user216171

+6

En realidad, se archivó como un error contra django: https://code.djangoproject.com/ticket/16335, pero resultó que la única buena solución fue transformarla en un dict, como ahora se muestra en [docs] (https://docs.djangoproject.com/en/dev/topics/templates/#variables) y está visible en [changeset] (https://code.djangoproject.com/ticket/16335) – Stefano

70

Puede evitar la copia a un nuevo dict desactivando la función predeterminada de defaultdict una vez que haya terminado de insertar nuevos valores:

new_data.default_factory = None 

Explicación

El template variable resolution algorithm in Django intentará resolver new_data.items como new_data['items'] primera, que se resuelve a una lista vacía cuando se utiliza defaultdict (lista).

Para desactivar el impago a una lista vacía y tienen Django fallar en new_data['items'] luego continuar los intentos de resolución de hasta llamar new_data.items(), la default_factory attribute of defaultdict se puede configurar para Ninguno.

+6

+1 - Esto es mucho más eficiente que la respuesta seleccionada, especialmente con un gran conjunto de diccionarios. – keithhackbarth

+0

¡Gran respuesta, la explicación ayudó mucho a entender el problema subyacente! – Blackeagle52

+0

Podría añadir que un {% para k, v en detauldictvar%} le permite iterar en el elemento del defaultdict incluso sin establecer el default_factory en None. Con la explicación de Sebastien ahora puedo entender por qué :-) – RobM