¿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"

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.


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.


@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.


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 %}

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 %}


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.


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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.