¿Cómo acceder a un elemento del diccionario en una plantilla de Django?

181

Me gustaría imprimir el número de votos que obtuvo cada opción. Tengo este código en una plantilla:

{% for choice in choices %}
    {{choice.choice}} - {{votes[choice.id]}} <br />
{% endfor %}

voteses solo un diccionario mientras que choiceses un objeto modelo.

Plantea una excepción con este mensaje:

"Could not parse the remainder"
Mohamed
fuente

Respuestas:

63

Para hacer eco / ampliar el comentario de Jeff, lo que creo que debería apuntar es simplemente una propiedad en su clase Choice que calcula el número de votos asociados con ese objeto:

class Choice(models.Model):
    text = models.CharField(max_length=200)

    def calculateVotes(self):
        return Vote.objects.filter(choice=self).count()

    votes = property(calculateVotes)

Y luego en su plantilla, puede hacer:

{% for choice in choices %}
    {{choice.choice}} - {{choice.votes}} <br />
{% endfor %}

La etiqueta de la plantilla, en mi humilde opinión, es un poco exagerada para esta solución, pero tampoco es una solución terrible. El objetivo de las plantillas en Django es aislarlo del código en sus plantillas y viceversa.

Probaría el método anterior y vería qué SQL genera el ORM, ya que no estoy seguro de la parte superior de mi cabeza si pre-almacenará en caché las propiedades y solo creará una subselección para la propiedad o si iterativamente / en- demanda ejecutar la consulta para calcular el recuento de votos. Pero si genera consultas atroces, siempre puede llenar la propiedad en su vista con los datos que ha recopilado usted mismo.

John Ewart
fuente
Gracias @ John Ewart, tu solución funcionó para mí. Soy novato en django y python y no puedo entender cómo obtener el sql que ORM generó.
Mohamed
Puede encontrar la respuesta a ese bit aquí: docs.djangoproject.com/en/dev/faq/models/… Es bastante simple, en realidad y puede mostrarse en su plantilla, o registrarse con una función de registro, pero tiene que recuerde activar DEBUG para que esto funcione.
John Ewart el
Esta solución es perfecta para un problema que he tenido con los modelos de motor de aplicaciones django + Google. Desearía poder votarte dos veces.
Conrad
55
Si bien funciona, no es muy eficiente. Está haciendo consultas SQL en un bucle (algo que debe evitar). Crear su propia etiqueta para hacer búsquedas de dict es fácil: @ register.filter def lookup (d, key): if d and isinstance (d, dict): return d.get (key)
dalore
Crear una clase es demasiado sobrecarga; Un diccionario mejor estructurado, combinado con la .itemsllamada (como se ilustra en una de las otras respuestas) es una solución mucho más simple.
Zags
285
choices = {'key1':'val1', 'key2':'val2'}

Aquí está la plantilla:

<ul>
{% for key, value in choices.items %} 
  <li>{{key}} - {{value}}</li>
{% endfor %}
</ul>

Básicamente, .itemses una palabra clave de Django que divide un diccionario en una lista de (key, value)pares, al igual que el método Python .items(). Esto permite la iteración sobre un diccionario en una plantilla de Django.

russian_spy
fuente
@anacarolinats (y otros) solo asegúrese de iterar sobre la clave, el valor de options.items. Aún debería funcionar.
OldTinfoil
¡Finalmente! ¡¡Gracias!! : D
djGrill
así que en el motor de plantillas no puedo usar (). Por cierto, gracias por mí.
BlaShadow el
66
Buena solución concisa a la pregunta. Para aclarar, itemses una llamada al método Python en el diccionario, no una palabra clave de Django. Como señala Alex Martelli , es básicamente lo mismo que iteritems. Como respondió Wilhelm, la búsqueda en el diccionario es la tercera en prioridad para las búsquedas de puntos. Si tiene un elemento en su diccionario llamado 'items', obtendrá ese valor en lugar de una lista de tuplas. Para probar: agréguelo {'items':'oops'}a su diccionario y obtendrá una lista con viñetas de la palabra 'oops'
cod3monk3y
1
Use collections.OrderedDict para controlar el orden de la iteración
dnalow
186

puedes usar la notación de puntos:

Las búsquedas de puntos se pueden resumir así: cuando el sistema de plantillas encuentra un punto en un nombre de variable, intenta las siguientes búsquedas, en este orden:

  • Búsqueda de diccionario (por ejemplo, foo ["bar"])
  • Búsqueda de atributos (por ejemplo, foo.bar)
  • Llamada de método (por ejemplo, foo.bar ())
  • Búsqueda de índice de lista (por ejemplo, foo [2])

El sistema usa el primer tipo de búsqueda que funciona. Es lógica de cortocircuito.

Wilhelm
fuente
44
En su caso, la elección es una variable. Al hacer .choice, se buscará el valor de la "elección" clave en lugar del valor de la elección clave.
ibz
+1 para la información, a pesar de que la pregunta era una especie de "adivina lo que estoy pensando". Gracias Wilhelm
eficker
1
Esto incluso funciona con diccionarios anidados. Código de Python: Código de my_dict[1][2]plantilla:my_dict.1.2
djsmith
2
@ JCLeitão Porque la versión correcta es d.key.1- tenga en cuenta la segunda.
Izkata
3
Sin embargo, compruebe los documentos sobre esto ... desde "1.6 docs.djangoproject.com/en/1.6/topics/templates/#variables ": Tenga en cuenta que se interpretará "bar" en una expresión de plantilla como {{foo.bar}} como una cadena literal y sin usar el valor de la variable "barra", si existe una en el contexto de la plantilla.
jamesc
25

Debe encontrar (o definir) una etiqueta de plantilla 'get', por ejemplo, aquí .

La definición de etiqueta:

@register.filter
def hash(h, key):
    return h[key]

Y se usa como:

{% for o in objects %}
  <li>{{ dictionary|hash:o.id }}</li>
{% endfor %}
Ned Batchelder
fuente
3
considerar h.get(key,'default_value')debido a KeyError
semiomante
9

Usar elementos del diccionario:

{% for key, value in my_dictionay.items %}
  <li>{{ key }} : {{ value }}</li>
{% endfor %}
Priyanshu Chauhan
fuente
6

Similar a la respuesta de @russian_spy:

<ul>
{% for choice in choices.items %} 
  <li>{{choice.0}} - {{choice.1}}</li>
{% endfor %}
</ul>

Esto podría ser adecuado para desglosar diccionarios más complejos.

Adam Starrh
fuente
3

Idealmente, crearía un método en el objeto de elección que se encontrara en los votos, o crearía una relación entre los modelos. También funcionaría una etiqueta de plantilla que realizara la búsqueda del diccionario.

Jeff Ober
fuente