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?

Stan
fuente

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 }}
culebrón
fuente
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
11
Creo que @Jeff se refería a la documentación del filtro de plantilla personalizada de Django
Jorge Leitao
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.

Paul Whipp
fuente
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 }}
Yuji 'Tomita' Tomita
fuente
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 }}
AmiNadimi
fuente
¿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_ }}
sexybear2
fuente
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 }}
Hielo Quemado
fuente
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 %}
Krishna
fuente
-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>
Yi Yang Apollo
fuente
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