Plantilla de Django cómo buscar un valor de diccionario con una variable


234
mydict = {"key1":"value1", "key2":"value2"}

La forma más habitual de las operaciones de búsqueda de un valor del diccionario en una plantilla de Django es {{ mydict.key1 }}, {{ mydict.key2 }}. ¿Qué pasa si la clave es una variable de bucle? es decir:

{% for item in list %} # where item has an attribute NAME
  {{ mydict.item.NAME }} # I want to look up mydict[item.NAME]
{% endfor %}

mydict.item.NAMEfalla ¿Cómo arreglar esto?

Respuestas:


362

Escriba un filtro de plantilla personalizado:

from django.template.defaulttags import register
...
@register.filter
def get_item(dictionary, key):
    return dictionary.get(key)

(Lo uso de .getmodo que si la clave está ausente, no devuelve ninguna. Si lo hace dictionary[key], levantará un KeyErrorentonces).

uso:

{{ mydict|get_item:item.NAME }}

16
Documentación de Django Custom Template Tag , para aquellos que encuentren esto en el futuro.
Jeff

282
¿Por qué esto no está integrado por defecto? :-(
Berislav Lopac


55
en Jinja2 {{mydict [key]}}
Evgeny

99
¿El filtro va en views.py, algunos filtros extra.py o qué archivo?
AlanSE

56

Obtenga tanto la clave como el valor del diccionario en el bucle:

{% for key, value in mydict.items %}
    {{ value }}
{% endfor %}

Esto me resulta más fácil de leer y evita la necesidad de una codificación especial. Normalmente necesito la clave y el valor dentro del ciclo de todos modos.


28
No pidió enumerar un dict (como se muestra): pidió obtener el valor del dict dada una clave variable. Su propuesta no proporciona solución.
Staggart

Es una solución (simplemente muy ineficiente) ya que puede enumerar los elementos del dict y luego coincidir con la clave de la lista.
DylanYoung

1
Tenga en cuenta que esto no funciona si el diccionario al que está intentando acceder contiene otro diccionario en su interior.
J0ANMM

Si sus valores son dictados, puede incluir otro bucle for para procesar sus claves y valores, pero es probable que la complejidad lo lleve a que valga la pena usar un filtro personalizado como se describe en la respuesta de @ culebron.
Paul Whipp

37

No puedes por defecto. El punto es el separador / disparador para la búsqueda de atributos / búsqueda de claves / corte.

Los puntos tienen un significado especial en la representación de plantillas. Un punto en un nombre de variable significa una búsqueda. Específicamente, cuando el sistema de plantillas encuentra un punto en un nombre variable, intenta las siguientes búsquedas, en este orden:

  • Diccionario de búsqueda. Ejemplo: foo ["bar"]
  • Búsqueda de atributos. Ejemplo: foo.bar
  • Lista de búsqueda de índice. Ejemplo: foo [bar]

Pero puede hacer un filtro que le permita pasar un argumento:

https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-filters

@register.filter(name='lookup')
def lookup(value, arg):
    return value[arg]

{{ mydict|lookup:item.name }}

1
Todavía lo usaría return value.get(arg)porque eso no arrojaría una excepción KeyError si la clave no está presente.
slajma

3

Para mí, la creación de un archivo de Python nombrado template_filters.pyen mi aplicación con el contenido siguiente hizo el trabajo

# coding=utf-8
from django.template.base import Library

register = Library()


@register.filter
def get_item(dictionary, key):
    return dictionary.get(key)

el uso es como lo que dijo culebrón:

{{ mydict|get_item:item.NAME }}

¿Por qué register = Library()? Qué hace ?
MD. Khairul Basar

2
Si desea que todas sus plantillas conozcan su nuevo filtro, debe registrarlo en la django.template.base.Libraryclase. al register = Library()instanciar esa clase y usar el filteranotador de funciones dentro de ella para satisfacer nuestras necesidades
AmiNadimi

2

Tuve una situación similar. Sin embargo, usé una solución diferente.

En mi modelo, creo una propiedad que realiza la búsqueda del diccionario. En la plantilla, luego uso la propiedad.

En mi modelo: -

@property
def state_(self):
    """ Return the text of the state rather than an integer """
    return self.STATE[self.state]

En mi plantilla: -

The state is: {{ item.state_ }}

1

Como no puedo comentar, permítanme hacer esto en forma de una respuesta:
para construir sobre la respuesta de culebrón o la respuesta de Yuji 'Tomita' Tomita , el diccionario pasado a la función tiene la forma de una cadena, así que tal vez use ast. literal_eval para convertir la cadena a un diccionario primero, como en este ejemplo .

Con esta edición, el código debería verse así:

@register.filter(name='lookup')
def lookup(value, arg):
    dictionary = ast.literal_eval(value)
    return value.get(arg)

{{ mydict|lookup:item.name }}

0

Medio ambiente: Django 2.2

  1. Código de ejemplo:


    from django.template.defaulttags import register

    @register.filter(name='lookup')
    def lookup(value, arg):
        return value.get(arg)

Puse este código en un archivo llamado template_filters.py en mi carpeta de proyecto llamada portfoliomgr

  1. No importa dónde coloque su código de filtro, asegúrese de tener __init__.py en esa carpeta

  2. Agregue ese archivo a la sección de bibliotecas en la sección de plantillas en su archivo projectfolder / settings.py. Para mí, es portfoliomgr / settings.py



    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
                'libraries':{
                    'template_filters': 'portfoliomgr.template_filters',
                }
            },
        },
    ]
  1. En su código html, cargue la biblioteca

    
    {% load template_filters %}

-2

env: django 2.1.7

ver:

dict_objs[query_obj.id] = {'obj': query_obj, 'tag': str_tag}
return render(request, 'obj.html', {'dict_objs': dict_objs})

modelo:

{% for obj_id,dict_obj in dict_objs.items %}
<td>{{ dict_obj.obj.obj_name }}</td>
<td style="display:none">{{ obj_id }}</td>
<td>{{ forloop.counter }}</td>
<td>{{ dict_obj.obj.update_timestamp|date:"Y-m-d H:i:s"}}</td>

1
El código de la plantilla {{ dict_obj.obj.obj_name }}es en este caso equivalente al código de Python dict_obj["obj"]["obj_name"], sin embargo, la pregunta es sobre el equivalente de dict_obj[obj][obj_name].
Flimm
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.