Szablon Django, jak wyszukać wartość słownika za pomocą zmiennej


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

Regularne sposób do wyszukiwania wartość słownika w szablonie Django jest {{ mydict.key1 }}, {{ mydict.key2 }}. Co jeśli klucz jest zmienną pętli? to znaczy:

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

mydict.item.NAMEzawodzi. Jak to naprawić?

Odpowiedzi:


362

Napisz niestandardowy filtr szablonu:

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

(Używam .gettak, że jeśli klucz jest nieobecny, nie zwraca żadnego. Jeśli to zrobisz dictionary[key], podniesie KeyErrora.)

stosowanie:

{{ mydict|get_item:item.NAME }}

16
Dokumentacja niestandardowego tagu szablonu Django dla osób, które znajdą to w przyszłości.
Jeff

281
Dlaczego nie jest to domyślnie wbudowane? :-(
Berislav Lopac

11
Myślę, że @Jeff oznaczało dokumentację Django Custom Template Filter
Jorge Leitao,

5
w Jinja2 {{mydict [key]}}
Evgeny

9
Czy filtr znajduje się w views.py, dodatkowych plikach filter.py lub jakim pliku?
AlanSE

56

Pobierz w pętli zarówno klucz, jak i wartość ze słownika:

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

Uważam to za łatwiejsze do odczytania i pozwala uniknąć specjalnego kodowania. I tak zwykle potrzebuję klucza i wartości w pętli.


28
Nie poprosił o wyliczenie dykta (jak pokazujesz) - poprosił o podanie wartości dykta ze względu na zmienny klucz. Twoja propozycja nie zapewnia rozwiązania.
Stuttgart

Jest to rozwiązanie (po prostu bardzo nieefektywne), ponieważ można wyliczyć pozycje dykta, a następnie dopasować do klucza z listy.
DylanYoung

1
Pamiętaj, że to nie działa, jeśli słownik, do którego próbujesz uzyskać dostęp, zawiera inny słownik.
J0ANMM

Jeśli twoje wartości są dyktami, możesz dołączyć kolejną pętlę for do przetwarzania ich kluczy i wartości, ale prawdopodobnie złożoność doprowadza cię do tego, że warto użyć niestandardowego filtra, jak opisano w odpowiedzi @ culebron.
Paul Whipp,

37

Nie możesz domyślnie. Kropka jest separatorem / wyzwalaczem dla wyszukiwania atrybutów / wyszukiwania klucza / plasterka.

Kropki mają specjalne znaczenie w renderowaniu szablonów. Kropka w nazwie zmiennej oznacza wyszukiwanie. W szczególności, gdy system szablonów napotyka kropkę w nazwie zmiennej, próbuje wykonać następujące wyszukiwania, w następującej kolejności:

  • Wyszukiwanie w słowniku Przykład: foo [„bar”]
  • Wyszukiwanie atrybutów. Przykład: foo.bar
  • Wyszukiwanie indeksu listy. Przykład: foo [bar]

Ale możesz utworzyć filtr, który pozwala przekazać argument:

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
Nadal bym używał, return value.get(arg)ponieważ nie rzucałby wyjątku KeyError, jeśli klucz nie jest obecny.
slajma

3

Dla mnie template_filters.pyzadanie polegało na utworzeniu pliku Pythona o nazwie w mojej aplikacji z poniższą zawartością

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

register = Library()


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

użycie jest podobne do tego, co powiedział culebrón:

{{ mydict|get_item:item.NAME }}

Dlaczego register = Library()? Co to robi ?
MD. Khairul Basar,

2
Jeśli chcesz, aby wszystkie twoje szablony wiedziały o twoim nowym filtrze, musisz zarejestrować go w django.template.base.Libraryklasie. przez register = Library()instancję tej klasy i wykorzystanie filterfunkcji Annotator wewnątrz niego dotrzeć naszą potrzebę.
AmiNadimi,

2

Miałem podobną sytuację. Użyłem jednak innego rozwiązania.

W moim modelu tworzę właściwość, która wyszukuje słownik. Następnie w szablonie korzystam z właściwości.

W moim modelu: -

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

W moim szablonie: -

The state is: {{ item.state_ }}

1

Ponieważ nie mogę komentować, pozwólcie, że zrobię to w formie odpowiedzi:
aby oprzeć się na odpowiedzi culebróna lub odpowiedzi Yuji „Tomita” Tomity , słownik przekazany do funkcji ma postać ciągu, więc może użyć ast. literal_eval, aby najpierw przekonwertować ciąg na słownik, tak jak w tym przykładzie .

Po tej edycji kod powinien wyglądać następująco:

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

{{ mydict|lookup:item.name }}

0

Środowisko: Django 2.2

  1. Przykładowy kod:


    from django.template.defaulttags import register

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

Umieszczam ten kod w pliku o nazwie template_filters.py w folderze projektu o nazwie portfoliomgr

  1. Bez względu na to, gdzie umieścisz kod filtra, upewnij się, że masz __init__.py w tym folderze

  2. Dodaj ten plik do sekcji bibliotek w sekcji szablonów w pliku projectfolder / settings.py. Dla mnie jest to 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. W kodzie HTML załaduj bibliotekę

    
    {% load template_filters %}

-2

env: django 2.1.7

widok:

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

szablon:

{% 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
Kod szablonu {{ dict_obj.obj.obj_name }}jest w tym przypadku równoważny kodowi Python dict_obj["obj"]["obj_name"], jednak pytanie dotyczy odpowiednika dict_obj[obj][obj_name].
Flimm
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.