Django-Vorlage zum Nachschlagen eines Wörterbuchwerts mit einer Variablen

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

Die normale Methode zum Nachschlagen eines Wörterbuchwerts in einer Django-Vorlage ist {{ mydict.key1 }}, {{ mydict.key2 }}. Was ist, wenn der Schlüssel eine Schleifenvariable ist? dh:

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

mydict.item.NAMEschlägt fehl. Wie kann ich das beheben?

Stan
quelle

Antworten:

361

Schreiben Sie einen benutzerdefinierten Vorlagenfilter:

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

(Ich benutze, .getdamit, wenn der Schlüssel fehlt, er keinen zurückgibt. Wenn Sie dies tun dictionary[key], wird ein KeyErrorDann ausgelöst .)

Verwendung:

{{ mydict|get_item:item.NAME }}
culebrón
quelle
16
Django Custom Template Tag-Dokumentation für diejenigen, die dies in Zukunft finden.
Jeff
281
Warum ist dies nicht standardmäßig eingebaut? :-(
Berislav Lopac
11
Ich denke, @ Jeff meinte Django Custom Template Filter Dokumentation
Jorge Leitao
5
in Jinja2 {{mydict [key]}}
Evgeny
9
Geht der Filter in views.py, einige zusätzliche filter.py oder in welche Datei?
AlanSE
55

Rufen Sie sowohl den Schlüssel als auch den Wert aus dem Wörterbuch in der Schleife ab:

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

Ich finde das leichter zu lesen und vermeide die Notwendigkeit einer speziellen Codierung. Normalerweise brauche ich sowieso den Schlüssel und den Wert in der Schleife.

Paul Whipp
quelle
28
Er hat nicht darum gebeten, ein Diktat aufzuzählen (wie Sie zeigen) - er hat darum gebeten, den Wert des Diktats mit einem variablen Schlüssel zu erhalten. Ihr Vorschlag bietet keine Lösung.
Staggart
Dies ist eine Lösung (nur sehr ineffizient), da Sie die Elemente des Diktats aufzählen und dann mit dem Schlüssel aus der Liste abgleichen können.
DylanYoung
1
Beachten Sie, dass dies nicht funktioniert, wenn das Wörterbuch, auf das Sie zugreifen möchten, ein anderes Wörterbuch enthält.
J0ANMM
Wenn es sich bei Ihren Werten um Diktate handelt, können Sie eine weitere for-Schleife einfügen, um deren Schlüssel und Werte zu verarbeiten. Aufgrund der Komplexität lohnt es sich jedoch wahrscheinlich, einen benutzerdefinierten Filter zu verwenden, wie in der Antwort von @ culebron beschrieben.
Paul Whipp
36

Sie können nicht standardmäßig. Der Punkt ist das Trennzeichen / der Auslöser für die Attributsuche / Schlüsselsuche / Slice.

Punkte haben beim Rendern von Vorlagen eine besondere Bedeutung. Ein Punkt in einem Variablennamen bedeutet eine Suche. Wenn das Vorlagensystem auf einen Punkt in einem Variablennamen stößt, werden die folgenden Suchvorgänge in dieser Reihenfolge ausgeführt:

  • Wörterbuchsuche. Beispiel: foo ["bar"]
  • Attributsuche. Beispiel: foo.bar
  • Listenindex-Suche. Beispiel: foo [bar]

Sie können jedoch einen Filter erstellen, mit dem Sie ein Argument übergeben können:

https://docs.djangoproject.com/de/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
quelle
Ich würde immer noch verwenden, return value.get(arg)da dies keine KeyError-Ausnahme auslösen würde, wenn der Schlüssel nicht vorhanden ist.
Slajma
3

Für mich hat das Erstellen einer Python-Datei mit dem Namen template_filters.pyin meiner App mit dem folgenden Inhalt den Job erledigt

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

register = Library()


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

Verwendung ist wie das, was Culebrón sagte:

{{ mydict|get_item:item.NAME }}
AmiNadimi
quelle
Warum register = Library()? Was tut es ?
MD. Khairul Basar
2
Wenn Sie möchten, dass alle Ihre Vorlagen über Ihren neuen Filter informiert sind, müssen Sie ihn unter django.template.base.Libraryclass registrieren . indem register = Library()wir diese Klasse instanziieren und den filterFunktionsanmerker darin verwenden, um unseren Bedarf zu decken.
AmiNadimi
2

Ich hatte eine ähnliche Situation. Ich habe jedoch eine andere Lösung verwendet.

In meinem Modell erstelle ich eine Eigenschaft, die die Wörterbuchsuche durchführt. In der Vorlage verwende ich dann die Eigenschaft.

In meinem Modell: -

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

In meiner Vorlage: -

The state is: {{ item.state_ }}
sexybear2
quelle
1

Da ich keinen Kommentar abgeben kann, lassen Sie mich dies in Form einer Antwort tun: Um auf der Antwort
von Culebrón oder der Antwort von Yuji 'Tomita' Tomita aufzubauen , hat das an die Funktion übergebene Wörterbuch die Form einer Zeichenfolge. Verwenden Sie also möglicherweise ast. literal_eval , um die Zeichenfolge zuerst in ein Wörterbuch zu konvertieren, wie in diesem Beispiel .

Bei dieser Bearbeitung sollte der Code folgendermaßen aussehen:

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

{{ mydict|lookup:item.name }}
BurntIce
quelle
0

Umwelt: Django 2.2

  1. Beispielcode:


    from django.template.defaulttags import register

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

Ich habe diesen Code in eine Datei mit dem Namen template_filters.py in meinem Projektordner mit dem Namen portfoliomgr eingefügt

  1. Unabhängig davon , wo Sie Ihren Filtercode ablegen , stellen Sie sicher, dass Sie __init__.py in diesem Ordner haben

  2. Fügen Sie diese Datei zum Abschnitt "Bibliotheken" im Abschnitt "Vorlagen" in Ihrer Datei "projectfolder / settings.py" hinzu. Für mich ist 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. Laden Sie in Ihren HTML-Code die Bibliothek

    
    {% load template_filters %}
Krishna
quelle
-2

env: django 2.1.7

Aussicht:

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

Vorlage:

{% 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
quelle
1
Der Vorlagencode entspricht {{ dict_obj.obj.obj_name }}in diesem Fall dem Python-Code dict_obj["obj"]["obj_name"], die Frage bezieht sich jedoch auf das Äquivalent von dict_obj[obj][obj_name].
Flimm