Jinja: Mustahil untuk mengulangi objek dengan elemen "item"

Dibuat pada 9 Jan 2017  ·  10Komentar  ·  Sumber: pallets/jinja

Server mengembalikan JSON ini:
{
"item": [1,2,3]
...
}

Upaya untuk mengulangi 'item' menghasilkan:
{% untuk el di data.items %}
....
TypeError: objek 'builtin_function_or_method' tidak dapat diubah

Di atas terjadi karena Python dict memiliki fungsi bawaan "items()".

Sebagai seorang suhu. solusi, saya memasang pengait dan mengganti nama kunci dalam respons JSON dari "item" menjadi "__items" lalu meneruskannya ke Jinja2. Pada saat itu, saya mengulangi atribut yang diganti namanya dengan baik:
{% untuk el dalam data.__item %}

Idealnya, Jinja2 harus mengabaikan fungsi bawaan dalam for-loop atau if-statement kecuali secara khusus dipanggil dengan notasi function().

Komentar yang paling membantu

Anda dapat menggunakan {% for el in data['items'] %} untuk memprioritaskan item. Ini juga tercakup dalam dokumentasi. http://jinja.pocoo.org/docs/2.9/templates/#variables

Semua 10 komentar

Anda dapat menggunakan {% for el in data['items'] %} untuk memprioritaskan item. Ini juga tercakup dalam dokumentasi. http://jinja.pocoo.org/docs/2.9/templates/#variables

Ini akan gagal jika respons JSON terkadang tidak menyertakan 'item' (katakanlah itu adalah atribut opsional dari respons). Dalam hal ini, {% for el in data['items'] %} juga akan menghasilkan:
TypeError: objek 'builtin_function_or_method' tidak dapat diubah

... karena item selalu didefinisikan (sebagai fungsi bawaan).

Dan ini adalah bug, IMO. Data['item'] tidak boleh bertabrakan dengan bawaan. Dengan kata lain, jika Anda ingin mengulangi atribut "item" opsional dengan bersih, Anda terpaksa mengganti namanya. Idealnya, seharusnya tidak demikian.

Mengapa respons JSON tidak menyertakan item? Saya tidak sepenuhnya yakin saya melihat masalahnya di sini. Tentunya Anda sudah tahu sebelumnya apa itu data Anda. Anda juga dapat di templat memeriksa kunci dengan operator in pada kamus.

Mengubah perilaku ini sama sekali tidak mungkin karena ribuan template akan rusak jika kami menghapus dukungan atribut/item ini.

Saya tidak menyarankan untuk menjatuhkan apa pun, hanya untuk membuatnya lebih ketat.

Masalahnya hari ini adalah ketika Anda menggunakan notasi pencarian eksplisit: data['items'] ia menemukan fungsi kamus bawaan dan seharusnya tidak . Python tidak melakukannya, begitu juga jinja. Jika seseorang perlu memanggil builtin (atau fungsi apa pun dalam hal ini), Anda memiliki notasi panggilan untuk itu: data.items()

Tidak yakin apakah akan sangat jelas untuk kasus khusus dict.items sana. Terutama karena itu masih gagal untuk tipe seperti dict khusus atau bahkan mungkin OrderedDict . Saya pikir lebih baik foo['items'] dalam kasus tersebut. Ini tidak super cantik tapi perilaku yang konsisten.

Satu-satunya kemungkinan "perbaikan/peretasan" yang dapat saya bayangkan untuk mengatasi ini dengan cara yang lebih baik adalah memeriksa apakah atribut biasa (yaitu bukan panggilan fungsi) digunakan dalam iterasi dan Anda mencoba mengulangi sesuatu yang tidak dapat diubah tetapi dapat dipanggil . Dalam hal ini mencoba item akan sangat kecil kemungkinannya untuk memecahkan kode yang ada. Namun, implementasi untuk perilaku seperti itu di Jinja mungkin akan sangat buruk;)

Mengapa ini kasus khusus? Saya meminta Jinja untuk berperilaku persis seperti Python. Secara khusus, foo['items'] harus menghasilkan None jika tidak ada "item" kunci yang dimasukkan pengguna di dalamnya. Hari ini, Jinja kembali menemukan fungsi bawaan dengan nama yang sama. Jadi lakukan saja apa yang dilakukan Python:

>>> print {}.get('items')
None

Btw, saya juga percaya bahwa notasi alternatif "foo.items" harus ditangani dengan baik juga, karena Anda perlu menggunakan "()" untuk memanggil callable, tetapi jika Anda memerlukan beberapa kompatibilitas mundur untuk foo.items untuk menemukan kunci atau memanggil fungsi secara otomatis, maka saya rasa itu terlalu buruk.

Logika Jinja untuk ['x'] dan .x adalah ini:

  • Periksa apakah item/attr (apa pun sintaks Anda di Python) ada, jika ya gunakan itu
  • Periksa apakah attr/item ("kebalikan" dari apa yang akan dilakukan sintaks Anda dengan Python) ada, jika ya gunakan itu
  • Gagal jika tidak ada

Jadi x.items memeriksa atribut dan karena ada atribut, ia menggunakannya. Logika ini bekerja seperti ini tidak peduli kontesnya. Memperbaiki ini akan membutuhkan logika pencarian atribut untuk berubah tergantung pada konteksnya. Dan bahkan itu akan menghasilkan situasi canggung seperti kode ini yang akan berfungsi:

{% for x in mydict.items %}

vs kode ini yang tidak akan berfungsi

{% set items = mydict.items %}
{% for x in items %}

Dan menjaga penanganan khusus dalam kasus ini tidak mungkin dilakukan tanpa melacak dari mana sebuah variabel berasal.

@slisznia Anda pada dasarnya meminta Jinja2 untuk sepenuhnya mengubah sistem pencarian atribut yang telah ada selama sekitar 7 tahun pada saat ini.

Ah, saya bahkan tidak melihat saran foo['bar'] tidak melakukan pencarian atribut. Itu ide yang buruk pasti! Apa yang salah dengan Anda hanya menggunakan for item in data.get('items', []) ?

@ThiefMaster mydict.get('items', []) tentu saja berfungsi, dan terima kasih telah menunjukkan metode lain selain mengganti nama kunci.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat