Template Django cara mencari nilai kamus dengan variabel

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

Dengan cara biasa untuk mencari nilai kamus di template Django adalah {{ mydict.key1 }}, {{ mydict.key2 }}. Bagaimana jika kuncinya adalah variabel loop? yaitu:

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

mydict.item.NAMEgagal Bagaimana cara memperbaikinya?

Stan
sumber

Jawaban:

362

Tulis filter templat khusus:

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

(Saya menggunakan .getsehingga jika kuncinya tidak ada, itu tidak mengembalikan apa pun. Jika Anda melakukannya dictionary[key]maka akan meningkatkan KeyError.)

pemakaian:

{{ mydict|get_item:item.NAME }}
culebrón
sumber
16
Dokumentasi Tag Template Kustom Django , untuk mereka yang menemukan ini di masa depan.
Jeff
282
Mengapa ini tidak bawaan secara bawaan? :-(
Berislav Lopac
11
Saya pikir @Jeff berarti dokumentasi Filter Template Kustom Django
Jorge Leitao
5
di Jinja2 {{mydict [key]}}
Evgeny
9
Apakah filter masuk dalam views.py, beberapa filter tambahan.py, atau file apa?
AlanSE
56

Ambil kunci dan nilai dari kamus di loop:

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

Saya menemukan ini lebih mudah dibaca dan menghindari perlunya pengkodean khusus. Saya biasanya membutuhkan kunci dan nilai di dalam loop.

Paul Whipp
sumber
28
Dia tidak meminta untuk menghitung dict (seperti yang Anda tunjukkan) - dia meminta untuk mendapatkan nilai dict tersebut dengan kunci variabel. Proposal Anda tidak memberikan solusi.
staggart
Ini adalah solusi (hanya sangat tidak efisien) karena Anda dapat menghitung item-item dict dan kemudian mencocokkan dengan kunci dari daftar.
DylanYoung
1
Perhatikan bahwa ini tidak berfungsi jika kamus yang Anda coba akses mengandung kamus lain di dalamnya.
J0ANMM
Jika nilai-nilai Anda adalah dicts, Anda bisa memasukkan yang lain untuk loop untuk memproses kunci dan nilai-nilai mereka tetapi kemungkinan kompleksitas membawa Anda ke arah itu layak menggunakan filter kustom seperti yang dijelaskan dalam jawaban @ culebron.
Paul Whipp
37

Anda tidak dapat secara default. Titik adalah pemisah / pemicu untuk pencarian atribut / pencarian kunci / slice.

Dots memiliki arti khusus dalam rendering template. Titik di nama variabel menandakan pencarian. Secara khusus, ketika sistem template menemukan sebuah titik dalam nama variabel, ia mencoba pencarian berikut, dalam urutan ini:

  • Pencarian kamus. Contoh: foo ["bar"]
  • Pencarian atribut. Contoh: foo.bar
  • Daftar-indeks pencarian. Contoh: foo [bar]

Tetapi Anda bisa membuat filter yang memungkinkan Anda menyampaikan argumen:

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
sumber
1
Saya masih akan menggunakan return value.get(arg)karena itu tidak akan membuang pengecualian KeyError jika kunci tidak ada.
slajma
3

Bagi saya membuat file python bernama template_filters.pydi App saya dengan konten di bawah melakukan pekerjaan

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

register = Library()


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

penggunaan seperti apa yang dikatakan culebrón:

{{ mydict|get_item:item.NAME }}
AmiNadimi
sumber
Mengapa register = Library()? Apa fungsinya?
MD. Khairul Basar
2
Jika Anda ingin semua template Anda tahu tentang filter baru Anda, maka Anda harus mendaftarkannya di bawah django.template.base.Librarykelas. oleh register = Library()kami instantiate kelas itu dan menggunakan filterfungsi annotator di dalamnya untuk mencapai kebutuhan kita.
AmiNadimi
2

Saya memiliki situasi yang serupa. Namun saya menggunakan solusi yang berbeda.

Dalam model saya, saya membuat properti yang melakukan pencarian kamus. Di template saya kemudian menggunakan properti.

Dalam model saya: -

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

Dalam templat saya: -

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

Karena saya tidak dapat berkomentar, izinkan saya melakukan ini dalam bentuk jawaban:
untuk membangun di atas jawaban culebrón atau jawaban Yuji 'Tomita' Tomita , kamus yang dialihkan ke fungsi adalah dalam bentuk string, jadi mungkin gunakan ast. literal_eval untuk mengonversi string ke kamus terlebih dahulu, seperti dalam contoh ini .

Dengan pengeditan ini, kode akan terlihat seperti ini:

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

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

Lingkungan: Django 2.2

  1. Kode contoh:


    from django.template.defaulttags import register

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

Saya memasukkan kode ini ke file bernama template_filters.py di folder proyek saya bernama portfoliomgr

  1. Di mana pun Anda meletakkan kode filter, pastikan Anda memiliki __init__.py di folder itu

  2. Tambahkan file itu ke bagian perpustakaan di bagian template di file projectfolder / settings.py Anda. Bagi saya, ini adalah 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. Dalam kode html Anda memuat perpustakaan

    
    {% load template_filters %}
Krishna
sumber
-2

env: Django 2.1.7

melihat:

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

templat:

{% 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>
Apollo Yi Yang
sumber
1
Kode templat {{ dict_obj.obj.obj_name }}dalam hal ini setara dengan kode Python dict_obj["obj"]["obj_name"], namun pertanyaannya adalah tentang yang setara dengan dict_obj[obj][obj_name].
Flimm