Шаблон Джанго як шукати значення словника зі змінною


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

Нормальний шлях для пошуку по словником значення в шаблоні Django є {{ mydict.key1 }}, {{ mydict.key2 }}. Що робити, якщо ключ є змінною циклу? тобто:

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

mydict.item.NAMEне вдається. Як це виправити?

Відповіді:


362

Напишіть спеціальний фільтр шаблонів:

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

(Я використовую .getтак, що якщо ключ відсутній, він не повертає жодного. Якщо ви dictionary[key]це зробите, тоді піднімається KeyError.)

використання:

{{ mydict|get_item:item.NAME }}

16
Документація тегів шаблонів тегів Django для тих, хто їх знайде в майбутньому.
Джефф

281
Чому це не вбудовано за замовчуванням? :-(
Берислав Лопак


5
в Jinja2 {{mydict [key]}}
Євгеній

9
Чи входить фільтр у Views.py, якийсь додатковий filter.py чи який файл?
AlanSE

56

Отримайте і ключ, і значення зі словника в циклі:

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

Мені це легше читати, і це уникає необхідності спеціального кодування. Зазвичай мені потрібні ключ і значення всередині циклу.


28
Він не просив перерахувати дикт (як ви показуєте) - він попросив отримати значення дикта, надавши змінний ключ. Ваша пропозиція не забезпечує рішення.
стаггарт

Це рішення (просто дуже неефективне), оскільки ви можете перерахувати елементи дикту, а потім зіставити з ключем зі списку.
DylanYoung

1
Зауважте, що це не працює, якщо словник, до якого ви намагаєтесь отримати доступ, містить інший словник.
J0ANMM

Якщо ваші значення - це дикти, ви можете включити інший цикл для обробки своїх ключів та значень, але, ймовірно, складність спричиняє вас до того, що варто використовувати спеціальний фільтр, як описано у відповіді @ culebron.
Пол Віпп

37

За замовчуванням ви не можете. Точка є роздільником / тригером для пошуку атрибутів / пошуку ключа / фрагмента.

Точки мають особливе значення у візуалізації шаблонів. Крапка в імені змінної означає посилання. Зокрема, коли система шаблонів стикається з точкою в імені змінної, вона намагається виконати такі пошукові підходи в такому порядку:

  • Пошук словника. Приклад: foo ["bar"]
  • Пошук атрибутів. Приклад: foo.bar
  • Пошук списку-індексу. Приклад: foo [bar]

Але ви можете створити фільтр, який дозволяє передавати аргумент:

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
Я б все-таки використовував, return value.get(arg)тому що це не призведе до виключення KeyError, якщо ключа немає.
слайма

3

Для мене створення файлу python, названого template_filters.pyв моєму додатку із вмістом нижче, зробив цю роботу

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

register = Library()


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

використання - це те, що сказав culebrón:

{{ mydict|get_item:item.NAME }}

Чому register = Library()? Що це робить ?
д.м.н. Хайрул Басар

2
Якщо ви хочете, щоб усі ваші шаблони знали про ваш новий фільтр, тоді вам потрібно зареєструвати його під django.template.base.Libraryкласом. по register = Library()ми створюємо цей клас і використовувати filterфункцію аннотатор всередині нього , щоб досягти нашої потреби.
AmiNadimi

2

У мене була схожа ситуація. Однак я застосував інше рішення.

У своїй моделі я створюю властивість, яка здійснює пошук словника. Потім у шаблоні я використовую властивість.

У моїй моделі: -

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

У моєму шаблоні: -

The state is: {{ item.state_ }}

1

Оскільки я не можу коментувати, дозвольте це зробити у вигляді відповіді:
щоб спиратися на відповідь кулеброна або відповідь Юджі "Томіта" Томіти , словник, переданий у функцію, є у вигляді рядка, тому, можливо, використовуйте ast. literal_eval, щоб перетворити рядок у словник спочатку, як у цьому прикладі .

При цьому редагуванні код повинен виглядати так:

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

{{ mydict|lookup:item.name }}

0

Навколишнє середовище: Django 2.2

  1. Приклад коду:


    from django.template.defaulttags import register

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

Я поклав цей код у файл з іменем template_filters.py в папці проекту з назвою portfoliomgr

  1. Незалежно від того, куди ви поставили код фільтра, переконайтеся, що у цій папці є __init__.py

  2. Додайте цей файл до розділу "Бібліотеки" у розділі "Шаблони" у файлі проекту / settings.py. Для мене це 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. У свій html-код завантажте бібліотеку

    
    {% load template_filters %}

-2

env: django 2.1.7

вид:

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

шаблон:

{% 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
Код шаблону {{ dict_obj.obj.obj_name }}в цьому випадку еквівалентний коду Python dict_obj["obj"]["obj_name"], проте питання стосується еквівалента dict_obj[obj][obj_name].
Flimm
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.