Django Şablon Değişkenleri ve Javascript


219

Django şablon oluşturucuyu kullanarak bir sayfa oluşturduğumda, bunları kullanarak sayfada işlemek için çeşitli değerler içeren bir sözlük değişkenine geçebilirim {{ myVar }}.

Javascript aynı değişken erişmek için bir yolu var mı (belki DOM kullanarak, nasıl Django değişkenleri erişilebilir hale bilmiyorum)? Ben aktarılan değişkenlerde bulunan değerlere dayalı bir AJAX araması kullanarak ayrıntıları aramak istiyorum.

Yanıtlar:


291

{{variable}}HTML doğrudan ikame edilir. Bir görünüm kaynağı yapın; "değişken" ya da onun gibi bir şey değildir. Sadece metin haline getirildi.

Bunu söyledikten sonra, JavaScript'inize bu tür bir ikame koyabilirsiniz.

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

Bu size "dinamik" javascript verir.


29
Bununla birlikte, bu çözüme göre , bunun enjeksiyon saldırılarına karşı savunmasız olduğunu unutmayın
Casebash

13
@Casebash: Bu gibi durumlar için escapejsfiltre var:escapejs('<>') -> u'\\u003C\\u003E'
Tomasz Zieliński

24
Sadece referans için eklemek için: "someDjangoVariable" JSON ise, & quot; kaldırmak için {{someDjangoVariable | safe}} kullandığınızdan emin olun.
Mark

4
Bu cevap sadece basit bir değişken için çalışır, karmaşık bir veri yapısı için çalışmaz. Bu durumda, en basit çözüm, veri yapısını çaprazlamak ve Javascript'te benzer bir kod oluşturmak için istemci tarafı kodu eklemektir. Karmaşık veri yapısı JSON biçimindeyse, başka bir çözüm onu ​​serileştirmek, sunucu tarafı kodundaki Django şablonuna serileştirilmiş bir JSON iletmek ve istemci tarafı kodundaki bir javascript nesnesindeki JSON serisinin serisini kaldırmaktır. Aşağıdaki cevaplardan biri bu alternatiften bahsediyor.
Alan Evangelista

14
javascript farklı bir dosyaya yazılırsa ne olur?
the_unknown_spirit

64

DİKKAT Django çekirdeğine benzer etiket ekleme ve bu şablon etiketi kullanıcı tarafından oluşturulan verilerle kullanılmaya başlanan olası XSS ​​güvenlik açıkları hakkında tartışma için 17419 numaralı bileti kontrol edin . Amaçneil'den yapılan açıklama , bilette dile getirilen endişelerin çoğunu tartışıyor.


Bunu yapmanın en esnek ve kullanışlı yolunun JS kodunda kullanmak istediğiniz değişkenler için bir şablon filtresi tanımlamak olduğunu düşünüyorum. Bu, verilerinizin düzgün bir şekilde kaçmasını ve verilerinizi dictve gibi karmaşık veri yapılarıyla kullanabilmenizi sağlar list. Bu yüzden bu cevabı çok sayıda upvotes ile kabul edilmiş bir cevap olmasına rağmen yazıyorum.

Şablon filtresi örneği:

// 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))

Bu şablon filtreleri, değişkeni JSON dizesine dönüştürür. Şöyle kullanabilirsiniz:

// myapp/templates/example.html

{% load js %}

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

3
Bu güzel çünkü sadece bazı Django şablon giriş değişkenlerinin Javascript'e kopyalanmasına izin veriyor ve sunucu tarafı kodunun Javascript tarafından hangi veri yapılarının kullanılması gerektiğini ve dolayısıyla Django şablonunu oluşturmadan önce JSON'a dönüştürülmesi gerektiğini bilmesine gerek yok. Bunu kullanın veya her zaman tüm Django değişkenlerini Javascript'e kopyalayın.
Alan Evangelista


1
@JorgeOrpinel Hayır, aynı değil. safeyalnızca uygun dönüşüm ve kaçış olmadan değeri güvenli olarak işaretler.
Yaroslav Admin

2
Daha sonra değişkeni django şablonunda nasıl görüntülersiniz?
kbdev

1
@Sandi geri gönderdiğimde ayrı bir JS dosyasında bir widget olması ve sayfa kaynak kodunda başlatmak yaygındı. Diyelim ki function myWidget(config) { /* implementation */ }JS dosyasında bildiriyorsunuz ve bazı sayfalarda kullandığınızdan daha fazla myWidget({{ pythonConfig | js }}). Ancak JS dosyalarında (fark ettiğiniz gibi) kullanamazsınız, bu yüzden sınırlamaları vardır.
Yaroslav Admin

51

Benim için çalışan bir çözüm, şablondaki gizli giriş alanını kullanmaktır

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

Sonra javascript değeri bu şekilde elde,

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

3
dikkatli olun. değişkeni / formu nasıl kullandığınıza bağlı olarak, kullanıcı istediği her şeyi girebilir.
AndyL

3
giriş alanınızı salt okunur olarak ayarlamak isteyebilirsiniz (bu bağlantıya bakın w3schools.com/tags/att_input_readonly.asp )
nu everest

Bir veritabanını değiştirmeyecek veya bir veritabanı sorgusuna gönderilmeyecek bir şey varsa, bu iyi olur. @AndyL
James111

3
Çocuklar ... kullanıcılar istediklerini her neyse yapabilirler. Tarayıcılar, günümüzde tam özellikli bir DOM denetçisi ve hata ayıklama araçlarıyla bunu çok kolaylaştırıyor. Hikayenin ahlakı: TÜM size sunucuda veri doğrulaması yapın .
user2867288

1
Lütfen bu değişkene harici bir JavaScript dosyasında nasıl erişeceğinizi söyleyebilir misiniz?
Ahtisham

27

Django 2.1 itibarıyla şablon etiketi inşa edilen yeni bu kullanım şeklini özellikle tanıtılmaktadır: json_script.

https://docs.djangoproject.com/en/3.0/ref/templates/builtins/#json-script

Yeni etiket, şablon değerlerini güvenli bir şekilde serileştirir ve XSS'ye karşı korur.

Django belgeleri alıntı:

JavaScript ile kullanıma hazır bir etikete sarılmış bir Python nesnesini JSON olarak güvenle çıkarır.


10

İşte çok kolay bir şekilde yapıyorum: Şablonum için base.html dosyamı değiştirdim ve altına koyuyorum:

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

javascript dosyalarında bir değişken kullanmak istediğinizde, ben bir DJdata sözlüğü oluşturmak ve bir json tarafından bağlama eklemek: context['DJdata'] = json.dumps(DJdata)

Umarım yardımcı olur!


Bunu kullanmayın, kod enjeksiyonuna (XSS) karşı savunmasızdır.
pcworld

8

Bir sözlük için, önce JSON'a kodlamak en iyisidir. Simplejson.dumps () kullanabilirsiniz veya App Engine'deki bir veri modelinden dönüştürmek istiyorsanız, GQLEncoder kütüphanesinden encode () kullanabilirsiniz.


1
Ben django 1.7 itibariyle 'simplejson' 'json' olduğuna dikkat edin.
fiveclubs

4

S.Lott'un önerdiği benzer sorun ve cevaplar benim için çalıştı.

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

Ancak burada büyük uygulama sınırlamalarına dikkat çekmek istiyorum. Javascript kodunuzu farklı bir dosyaya koymayı ve bu dosyayı şablonunuza eklemeyi planlıyorsanız. Bu işe yaramaz.

Bu, yalnızca ana şablon ve javascript kodu aynı dosyadayken çalışır. Muhtemelen django ekibi bu sınırlamayı aşabilir.


1
Bunu nasıl yenebiliriz?
Csaba Toth

2
Bunun üstesinden gelmek için, statik Javascript dosyasını eklemeden hemen önce gösterilen örnek gibi global Javascript değişkenlerini yerleştirebilirsiniz. Statik Javascript dosyanız tüm global değişkenlere bu şekilde erişebilecektir.
Bobort

Bunu kullanmayın, kod enjeksiyonuna (XSS) karşı savunmasızdır.
pcworld

Verileri sunucu tarafında geçerli kılar.
Muhammed Faizan Fareed

4

Ben de bununla mücadele ediyorum. Yüzeyde yukarıdaki çözümlerin çalışması gerekiyor gibi görünüyor. Bununla birlikte, django mimarisi, her html dosyasının kendi işlenmiş değişkenlerine sahip olmasını gerektirir (yani {{contact}}, işlenir contact.html, {{posts}}örneğin index.html, vb. Öte yandan, <script>etiketler sonra görünen {%endblock%}içinde base.htmlhangi contact.htmlve index.htmlinherit. Bu temel olarak,

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

değişkeni başarısız olur, çünkü değişken ve komut dosyası aynı dosyada birlikte bulunamaz.

Sonunda geldi ve benim için çalıştım basit bir çözüm, sadece id ile bir etiket ile değişkeni sarmak ve daha sonra js dosyasında, böyle başvurmak oldu:

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

ve sonra:

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

ve sadece şunlardır <script src="static/js/somecode.js"></script>içinde base.htmlher zamanki gibi. Tabii ki bu sadece içeriği almakla ilgilidir . Güvenlikle ilgili olarak, diğer cevapları takip edin.


HTML kodlu alan varlıklar da JS değişkeninin bir parçası olacağından, muhtemelen .textContentbunun yerine kullanmak istersiniz .innerHTML. Ama o zaman bile 1: 1 üretilemeyebilir (emin değilim).
pcworld

Bir açıklama . Değişkenlerde (dinamik olarak formda oluşturulan kimlikleri kullanarak) alan değerlerini yakalamak için benzer bir yol kullanın ve çalışıyor (ancak yalnızca bir form kümesi satırı için ). Ne elde edemiyorum , el ile (yani döngü için kullanarak bir html tablosunda ) doldurulmuş olan form kümesi alanlarının tüm satırlarından değerleri yakalamaktır . Görselleştireceğiniz gibi değişkenlere yalnızca son form kümesi satırının geçirildiği değişkenler ve for döngüsü form kümesi satırları boyunca ilerledikçe önceki değerlerin üzerine yazılır. Bunun bir yolu var mı?
user12379095

3

Yine bir JavaScript nesne dinamik Sayfada komut dosyası içine yerleştirilir olmayı gerektiren metinler gibi bir Django alanda depolanan bir JavaScript nesnesi için, her ikisini de kullanmak gerekmez escapejsve JSON.parse():

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

Django's escapejs, alıntıyı düzgün şekilde işler ve JSON.parse()dizeyi tekrar JS nesnesine dönüştürür.


2

Bir değişkeni harici bir .js komut dosyasına geçirmek istiyorsanız, komut dosyası etiketinizden önce genel bir değişken bildiren başka bir komut dosyası etiketi kullanmanız gerektiğini unutmayın.

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

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

data görünümde her zamanki gibi tanımlanır get_context_data

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

Küresel olarak bir değişken bildiren kısım aslında yardımcı oldu.
Rahul

Yukarıdaki gibi şablonlardan js değişkenlerine veri oluşturursanız, aynı sayfaya (global hale getirin) dönüştürülmelidir ve diğer kod ayrı js dosyasına gider. Sunucu tarafında veri geçerli olmalıdır, çünkü kullanıcı tarayıcıdan değişebilir.
Muhammed Faizan Fareed

1

Ben Django 2.1 bu şekilde kullanın ve benim için çalışır ve bu şekilde güvenli (başvuru) :

Django tarafı:

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

Html tarafı:

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

0

dizi değişkeninizin bir dizede bildirildiği komut dosyasının tamamını aşağıdaki gibi bir araya getirebilirsiniz,

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>"

aşağıdaki gibi bir dize oluşturur

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

bu dizeye sahip olduktan sonra, şablona göndermelisiniz

views.py

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

şablonda alırsınız ve ihtiyacınız olan javascript kodundan hemen önce, htm kodu olarak edebi bir şekilde yorumlarsınız, örneğin

şablon

{{ prueba|safe  }}

ve aşağıda kodunuzun geri kalanı, örnekte kullanılacak değişkenin data2 olduğunu unutmayın.

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

bu şekilde veri türünü koruyacaksınız, bu durumda bir düzenleme


Bunu yalnızca aaasayı içereceğinden eminseniz kullanın , aksi takdirde XSS (komut dosyası enjeksiyonu) mümkündür.
pcworld

0

Javascript içinde benim için çalışan iki şey var:

'{{context_variable|escapejs }}'

ve diğer: views.py içinde

from json import dumps as jdumps

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

ve html'de:

{{ message|safe }}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.