Variabel Template Django dan Javascript


219

Ketika saya merender halaman menggunakan renderer template Django, saya bisa memberikan variabel kamus yang berisi berbagai nilai untuk memanipulasi mereka di halaman menggunakan {{ myVar }}.

Apakah ada cara untuk mengakses variabel yang sama dalam Javascript (mungkin menggunakan DOM, saya tidak tahu bagaimana Django membuat variabel dapat diakses)? Saya ingin dapat mencari rincian menggunakan pencarian AJAX berdasarkan nilai-nilai yang terkandung dalam variabel yang diteruskan.

Jawaban:


291

Ini {{variable}}diganti secara langsung ke dalam HTML. Apakah sumber tampilan; itu bukan "variabel" atau semacamnya. Itu hanya teks yang dirender.

Karena itu, Anda dapat memasukkan subtitusi ini ke dalam JavaScript Anda.

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}";
</script>

Ini memberi Anda javascript "dinamis".


29
Perhatikan bahwa menurut solusi ini , ini rentan terhadap serangan injeksi
Casebash

13
@Casebash: Untuk acara-acara seperti itu escapejsada filter:escapejs('<>') -> u'\\u003C\\u003E'
Tomasz Zieliński

24
Untuk menambahkan referensi ini: jika "someDjangoVariable" adalah JSON, pastikan untuk menggunakan {{someDjangoVariable | safe}} untuk menghapus & quot;
Markus

4
Jawaban ini hanya berfungsi untuk variabel sederhana, itu tidak berfungsi untuk struktur data yang kompleks. Dalam hal ini, solusi paling sederhana adalah menambahkan kode sisi klien untuk melintasi struktur data dan membangun yang serupa di Javascript. Jika struktur data yang kompleks adalah dalam format JSON, solusi lain adalah membuat serialisasi, meneruskan JSON berseri ke template Django dalam kode sisi-server dan deserialisasi JSON dalam objek javascript dalam kode sisi-klien. Satu jawaban di bawah menyebutkan alternatif ini.
Alan Evangelista

14
bagaimana jika javascript ditulis dalam file yang berbeda?
the_unknown_spirit

64

HATI-HATI Periksa tiket # 17419 untuk diskusi tentang menambahkan tag serupa ke inti Django dan kemungkinan kerentanan XSS yang diperkenalkan dengan menggunakan tag templat ini dengan data yang dibuat pengguna. Komentar dari amacneil membahas sebagian besar kekhawatiran yang muncul dalam tiket.


Saya pikir cara paling fleksibel dan praktis untuk melakukan ini adalah dengan mendefinisikan filter template untuk variabel yang ingin Anda gunakan dalam kode JS. Ini memungkinkan Anda untuk memastikan, bahwa data Anda lolos dengan benar dan Anda dapat menggunakannya dengan struktur data yang kompleks, seperti dictdan list. Itu sebabnya saya menulis jawaban ini meskipun ada jawaban yang diterima dengan banyak upvotes.

Berikut ini contoh filter templat:

// myapp/templatetags/js.py

from django.utils.safestring import mark_safe
from django.template import Library

import json


register = Library()


@register.filter(is_safe=True)
def js(obj):
    return mark_safe(json.dumps(obj))

Filter template ini mengonversi variabel menjadi string JSON. Anda dapat menggunakannya seperti ini:

// myapp/templates/example.html

{% load js %}

<script type="text/javascript">
    var someVar = {{ some_var | js }};
</script>

3
Itu bagus karena memungkinkan menyalin hanya beberapa variabel input template Django ke Javascript dan kode sisi server tidak perlu tahu struktur data mana yang harus digunakan oleh Javascript dan karenanya dikonversi ke JSON sebelum merender template Django. Baik gunakan ini atau selalu salin semua variabel Django ke Javascript.
Alan Evangelista


1
@JorgeOrpinel Tidak, tidak sama. safehanya menandai nilai sebagai aman, tanpa konversi dan melarikan diri yang tepat.
Yaroslav Admin

2
Bagaimana Anda kemudian menampilkan variabel dalam template Django?
kbdev

1
@Sandi kembali ketika saya mempostingnya, itu biasa untuk memiliki widget di file JS terpisah dan menginisialisasi dalam kode sumber halaman. Jadi katakanlah Anda mendeklarasikan function myWidget(config) { /* implementation */ }dalam file JS dan daripada Anda menggunakannya pada beberapa halaman menggunakan myWidget({{ pythonConfig | js }}). Tetapi Anda tidak dapat menggunakannya dalam file JS (seperti yang Anda perhatikan), sehingga memiliki keterbatasan.
Yaroslav Admin

51

Solusi yang berfungsi untuk saya adalah menggunakan bidang input tersembunyi di template

<input type="hidden" id="myVar" name="variable" value="{{ variable }}">

Kemudian dapatkan nilai dalam javascript dengan cara ini,

var myVar = document.getElementById("myVar").value;

3
berhati-hatilah. tergantung pada bagaimana Anda menggunakan variabel / formulir, pengguna dapat memasukkan apa pun yang mereka inginkan.
AndyL

3
Anda mungkin juga ingin mengatur bidang input Anda menjadi hanya baca (lihat tautan ini w3schools.com/tags/att_input_readonly.asp )
nu everest

Jika itu adalah sesuatu yang tidak akan mengubah database atau tidak akan dikirim ke permintaan database, ini akan baik-baik saja. @AndyL
James111

3
Guys ... pengguna dapat melakukan apa yang mereka inginkan. Browser membuatnya sangat mudah saat ini dengan inspektur DOM berfitur lengkap dan alat debugging. Moral dari cerita: lakukan SEMUA validasi data Anda di server .
user2867288

1
Dapatkah ada yang memberi tahu saya bagaimana Anda mengakses variabel itu dalam file JavaScript eksternal?
Ahtisham


10

Inilah yang saya lakukan dengan sangat mudah: Saya memodifikasi file base.html untuk template saya dan meletakkannya di bagian bawah:

{% if DJdata %}
    <script type="text/javascript">
        (function () {window.DJdata = {{DJdata|safe}};})();
    </script>
{% endif %}

kemudian ketika saya ingin menggunakan variabel dalam file javascript, saya membuat kamus DJdata dan saya menambahkannya ke konteks oleh json: context['DJdata'] = json.dumps(DJdata)

Semoga ini bisa membantu!


Jangan gunakan ini, ini rentan terhadap injeksi skrip (XSS).
pcworld

8

Untuk kamus, Anda sebaiknya melakukan enkode ke JSON terlebih dahulu. Anda bisa menggunakan simplejson.dumps () atau jika Anda ingin mengonversi dari model data di App Engine, Anda bisa menggunakan encode () dari pustaka GQLEncoder.


1
Perhatikan bahwa 'simplejson' menjadi 'json' pada Django 1.7, saya percaya.
fiveclubs

4

Saya menghadapi masalah yang sama dan jawaban yang disarankan oleh S.Lott bekerja untuk saya.

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}"
</script>

Namun saya ingin menunjukkan batasan implementasi utama di sini. Jika Anda berencana untuk meletakkan kode javascript Anda di file yang berbeda dan memasukkan file itu ke dalam template Anda. Ini tidak akan berhasil.

Ini bekerja hanya ketika Anda template utama dan kode javascript di file yang sama. Mungkin tim Django dapat mengatasi keterbatasan ini.


1
Bagaimana kita bisa mengatasi ini?
Csaba Toth

2
Untuk mengatasinya, Anda dapat menempatkan variabel Javascript global seperti contoh yang ditunjukkan tepat sebelum Anda menyertakan file Javascript statis. File Javascript statis Anda akan memiliki akses ke semua variabel global dengan cara itu.
Bobort

Jangan gunakan ini, ini rentan terhadap injeksi skrip (XSS).
pcworld

Mereka dapat memvalidasi data di sisi server.
Muhammad Faizan Fareed

4

Saya telah berjuang dengan ini juga. Di permukaan, tampaknya solusi di atas harus bekerja. Namun, arsitektur Django mensyaratkan bahwa setiap file html memiliki variabel yang dirender sendiri (yaitu, {{contact}}diberikan ke contact.html, sementara {{posts}}pergi ke misalnya index.htmldan seterusnya). Di sisi lain, <script>tag muncul setelah {%endblock%}in base.htmldari mana contact.htmldan index.htmlmewarisi. Ini pada dasarnya berarti bahwa semua solusi termasuk

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>

pasti gagal, karena variabel dan skrip tidak dapat hidup berdampingan dalam file yang sama.

Solusi sederhana yang akhirnya saya buat, dan bekerja untuk saya, adalah dengan hanya membungkus variabel dengan tag dengan id dan kemudian merujuknya dalam file js, seperti:

// index.html
<div id="myvar">{{ myVar }}</div>

lalu:

// somecode.js
var someVar = document.getElementById("myvar").innerHTML;

dan hanya termasuk <script src="static/js/somecode.js"></script>dalam base.htmlseperti biasa. Tentu saja ini hanya tentang mendapatkan konten. Mengenai keamanan, cukup ikuti jawaban lain.


Anda mungkin ingin menggunakan .textContentsebagai gantinya .innerHTML, karena jika tidak entitas yang mendapatkan HTML-encoded akan menjadi bagian dari variabel JS juga. Tetapi bahkan saat itu mungkin tidak direproduksi 1: 1 (Saya tidak yakin).
pcworld

Klarifikasi . Saya menggunakan cara yang mirip untuk menangkap nilai bidang dalam variabel (menggunakan ID yang dibuat secara dinamis dalam formulir), dan itu berfungsi (tetapi hanya untuk satu baris formset ). Apa yang saya tidak bisa menyiasati, adalah untuk menangkap nilai dari semua baris bidang formset , yang sedang diisi secara manual (yaitu dalam tabel html menggunakan untuk loop ). Saat Anda akan memvisualisasikan variabel hanya baris formset terakhir dilewatkan ke variabel, dan nilai-nilai sebelum yang ditimpa dengan nilai-nilai yang terakhir sebagai untuk loop berlanjut melalui baris formset. Apakah ada cara untuk melakukannya?
user12379095

3

Untuk objek JavaScript yang disimpan dalam bidang Django sebagai teks, yang perlu lagi menjadi objek JavaScript yang disisipkan secara dinamis ke dalam skrip on-page, Anda perlu menggunakan keduanya escapejsdan JSON.parse():

var CropOpts = JSON.parse("{{ profile.last_crop_coords|escapejs }}");

Django escapejsmenangani kutipan dengan benar, dan JSON.parse()mengubah string kembali menjadi objek JS.


2

Perhatikan, bahwa jika Anda ingin meneruskan variabel ke skrip .js eksternal maka Anda harus mengawali tag skrip Anda dengan tag skrip lain yang mendeklarasikan variabel global.

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>

<script type="text/javascript" src="{% static "scripts/my_script.js" %}"></script>

data didefinisikan dalam tampilan seperti biasa di get_context_data

def get_context_data(self, *args, **kwargs):
    context['myVar'] = True
    return context

Bagian untuk mendeklarasikan variabel secara global sebenarnya sangat membantu.
Rahul

jika Anda merender data menjadi variabel js dari template seperti di atas maka harus merender ke halaman yang sama (menjadikannya global) dan kode lainnya masuk ke file js yang terpisah. Di sisi server harus valid data karena pengguna dapat berubah dari browser.
Muhammad Faizan Fareed

1

Saya menggunakan cara ini di Django 2.1 dan bekerja untuk saya dan cara ini aman (referensi) :

Sisi Django:

def age(request):
    mydata = {'age':12}
    return render(request, 'test.html', context={"mydata_json": json.dumps(mydata)})

Sisi html:

<script type='text/javascript'>
     const  mydata = {{ mydata_json|safe }};
console.log(mydata)
 </script>

0

Anda bisa merakit seluruh skrip tempat variabel array Anda dinyatakan dalam sebuah string, seperti berikut,

views.py

    aaa = [41, 56, 25, 48, 72, 34, 12]
    prueba = "<script>var data2 =["
    for a in aaa:
        aa = str(a)
        prueba = prueba + "'" + aa + "',"
    prueba = prueba + "];</script>"

yang akan menghasilkan string sebagai berikut

prueba = "<script>var data2 =['41','56','25','48','72','34','12'];</script>"

setelah memiliki string ini, Anda harus mengirimnya ke templat

views.py

return render(request, 'example.html', {"prueba": prueba})

dalam template Anda menerimanya dan menafsirkannya dengan cara sastra sebagai kode htm, tepat sebelum kode javascript di mana Anda membutuhkannya, misalnya

templat

{{ prueba|safe  }}

dan di bawah itu adalah sisa kode Anda, perlu diingat bahwa variabel yang digunakan dalam contoh adalah data2

<script>
 console.log(data2);
</script>

dengan cara itu Anda akan menyimpan tipe data, yang dalam hal ini adalah pengaturan


Gunakan ini hanya jika Anda yakin itu aaahanya akan berisi angka, jika tidak XSS (injeksi skrip) dimungkinkan.
pcworld

0

Ada dua hal yang berhasil bagi saya di dalam Javascript:

'{{context_variable|escapejs }}'

dan lainnya: Di views.py

from json import dumps as jdumps

def func(request):
    context={'message': jdumps('hello there')}
    return render(request,'index.html',context)

dan di html:

{{ message|safe }}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.