Шаблон Django, как искать значение словаря с переменной

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 }}
culebrón
источник
16
Документация Django Custom Template Tag для тех, кто найдет это в будущем.
Джефф
282
Почему это не встроено по умолчанию? :-(
Берислав Лопач
11
Я думаю, что @Jeff имел в виду документацию к пользовательскому
Хорхе Лейтао,
5
в Jinja2 {{mydict [key]}}
Евгений
9
Фильтр идет в views.py, какие-то дополнительные filters.py или в какой файл?
AlanSE
56

Получите ключ и значение из словаря в цикле:

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

Я считаю, что это легче читать, и это избавляет от необходимости специального кодирования. Обычно мне все равно нужен ключ и значение внутри цикла.

Пол Уипп
источник
28
Он не просил перечислить dict (как вы показываете) - он попросил получить значение dict с помощью переменного ключа. Ваше предложение не дает решения.
августа
Это решение (просто очень неэффективное), так как вы можете перечислить элементы dict, а затем сопоставить их с ключом из списка.
DylanYoung
1
Обратите внимание, что это не работает, если словарь, к которому вы пытаетесь получить доступ, содержит другой словарь внутри.
J0ANMM
Если ваши значения являются диктатами, вы можете включить другой цикл for для обработки их ключей и значений, но, скорее всего, сложность приведет вас к тому, что стоит использовать собственный фильтр, как описано в ответе @ 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)

использование похоже на то, что сказал знаменитость:

{{ mydict|get_item:item.NAME }}
AmiNadimi
источник
Почему 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_ }}
sexybear2
источник
1

Поскольку я не могу комментировать, позвольте мне сделать это в форме ответа:
чтобы построить ответ culebrón или Yuji 'Tomita' Tomita , словарь, переданный в функцию, имеет форму строки, поэтому, возможно, используйте ast. literal_eval, чтобы сначала преобразовать строку в словарь, как в этом примере .

С этим редактированием код должен выглядеть так:

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

{{ mydict|lookup:item.name }}
BurntIce
источник
0

Окружение: Джанго 2.2

  1. Пример кода:


    from django.template.defaulttags import register

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

Я поместил этот код в файл с именем template_filters.py в папке моего проекта с именем portfolioiomgr

  1. Независимо от того, куда вы положили код фильтра, убедитесь, что в этой папке есть __init__.py

  2. Добавьте этот файл в раздел библиотек в разделе шаблонов в файле projectfolder / settings.py. Для меня это портфолио / 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