Django Template Variabili e Javascript


219

Quando eseguo il rendering di una pagina utilizzando il renderer modello Django, posso passare una variabile del dizionario contenente vari valori per manipolarli nella pagina utilizzando {{ myVar }}.

C'è un modo per accedere alla stessa variabile in Javascript (forse usando il DOM, non so come Django renda accessibili le variabili)? Voglio essere in grado di cercare i dettagli utilizzando una ricerca AJAX basata sui valori contenuti nelle variabili trasmesse.

Risposte:


291

Il {{variable}}viene sostituito direttamente nell'HTML. Fare una vista sorgente; non è una "variabile" o qualcosa del genere. È solo il testo renderizzato.

Detto questo, puoi inserire questo tipo di sostituzione nel tuo JavaScript.

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

Questo ti dà javascript "dinamico".


29
Si noti che secondo questa soluzione , questo è vulnerabile agli attacchi di iniezione
Casebash,

13
@Casebash: per tali occasioni escapejsesiste un filtro:escapejs('<>') -> u'\\u003C\\u003E'
Tomasz Zieliński,

24
Solo per aggiungere a questo come riferimento: se "someDjangoVariable" è JSON, assicurati di usare {{someDjangoVariable | safe}} per rimuovere il & quot;
Segna il

4
Questa risposta funziona solo per una semplice variabile, non funziona per una struttura di dati complessa. In questo caso, la soluzione più semplice è aggiungere codice lato client per attraversare la struttura dei dati e crearne uno simile in Javascript. Se la complessa struttura dati è in formato JSON, un'altra soluzione è serializzarla, passare un JSON serializzato al modello Django nel codice lato server e deserializzare il JSON in un oggetto javascript nel codice lato client. Una risposta sotto menziona questa alternativa.
Alan Evangelista,

14
cosa succede se javascript è scritto in un altro file?
the_unknown_spirit,

64

ATTENZIONE Controllare il ticket n. 17419 per la discussione sull'aggiunta di tag simili nel core di Django e le possibili vulnerabilità XSS introdotte utilizzando questo tag modello con i dati generati dall'utente. Il commento di amacneil discute la maggior parte delle preoccupazioni sollevate nel biglietto.


Penso che il modo più flessibile e pratico per farlo sia quello di definire un filtro template per le variabili che vuoi usare nel codice JS. Ciò consente di garantire che i dati vengano salvati correttamente e di poterli utilizzare con strutture dati complesse, come dicte list. Ecco perché scrivo questa risposta nonostante ci sia una risposta accettata con molti voti positivi.

Ecco un esempio di filtro modello:

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

Questo modello di filtri converte la variabile in stringa JSON. Puoi usarlo così:

// myapp/templates/example.html

{% load js %}

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

3
Ciò è utile perché consente di copiare solo alcune variabili di input del modello Django in Javascript e il codice lato server non ha bisogno di sapere quali strutture di dati devono essere utilizzate da Javascript e quindi convertite in JSON prima di eseguire il rendering del modello Django. Usa questo o copia sempre tutte le variabili Django in Javascript.
Alan Evangelista,


1
@JorgeOrpinel No, non è lo stesso. safesegna solo il valore come sicuro, senza una corretta conversione e fuga.
Yaroslav Admin,

2
Come si visualizza quindi la variabile nel modello django?
kbdev,

1
@Sandi quando l'ho pubblicato era normale avere un widget in un file JS separato e inizializzarlo nel codice sorgente della pagina. Quindi diciamo che dichiari function myWidget(config) { /* implementation */ }nel file JS e che lo usi in alcune pagine usando myWidget({{ pythonConfig | js }}). Ma non puoi usarlo nei file JS (come hai notato), quindi ha i suoi limiti.
Yaroslav Admin,

51

Una soluzione che ha funzionato per me sta usando il campo di input nascosto nel modello

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

Quindi ottenere il valore in javascript in questo modo,

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

3
diffidare però. a seconda di come usi la variabile / modulo, l'utente può inserire quello che vuole.
AndyL,

3
potresti anche voler impostare il tuo campo di input in sola lettura (vedi questo link w3schools.com/tags/att_input_readonly.asp )
nu everest

Se si tratta di qualcosa che non modificherà un database o che non verrà inviato a una query del database, ciò andrebbe bene. @AndyL
James111

3
Ragazzi ... gli utenti possono comunque fare ciò che vogliono. I browser lo rendono così facile al giorno d'oggi con un ispettore DOM completo e strumenti di debug. Morale della storia: fai TUTTI i tuoi dati di convalida sul server .
user2867288

1
Qualcuno può dirmi come accederesti a quella variabile in un file JavaScript esterno?
Ahtisham,


10

Ecco cosa sto facendo molto facilmente: ho modificato il mio file base.html per il mio modello e l'ho messo in fondo:

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

quindi quando voglio usare una variabile nei file javascript, creo un dizionario DJdata e lo aggiungo al contesto da un json: context['DJdata'] = json.dumps(DJdata)

Spero che sia d'aiuto!


Non usarlo, è vulnerabile all'iniezione di script (XSS).
pcworld,

8

Per un dizionario, è meglio prima codificare in JSON. È possibile utilizzare simplejson.dumps () o se si desidera convertire da un modello di dati in App Engine, è possibile utilizzare encode () dalla libreria GQLEncoder.


1
Si noti che "simplejson" è diventato "json" a partire da django 1.7, credo.
fiveclubs,

4

Stavo affrontando un problema simile e la risposta suggerita da S.Lott ha funzionato per me.

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

Tuttavia, vorrei sottolineare qui importanti limiti di attuazione . Se stai pianificando di inserire il tuo codice javascript in un altro file e includerlo nel tuo modello. Questo non funzionerà.

Funziona solo quando il tuo modello principale e il codice javascript si trovano nello stesso file. Probabilmente il team Django può affrontare questa limitazione.


1
Come possiamo superare questo?
Csaba Toth,

2
Per ovviare a questo, è possibile posizionare variabili Javascript globali come nell'esempio mostrato appena prima di includere il file Javascript statico. Il tuo file Javascript statico avrà accesso a tutte le variabili globali in quel modo.
Bobort

Non usarlo, è vulnerabile all'iniezione di script (XSS).
pcworld,

Possono validare dati sul lato server.
Muhammad Faizan ha pagato il

4

Ho avuto difficoltà anche con questo. A prima vista sembra che le soluzioni di cui sopra dovrebbero funzionare. Tuttavia, l'architettura django richiede che ogni file html abbia le proprie variabili renderizzate (ovvero, {{contact}}è renderizzato contact.html, mentre {{posts}}va ad esempio index.htmle così via). D'altra parte, <script>i tag compaiono dopo l' {%endblock%}in base.htmlda cui contact.htmle index.htmlEredita. Ciò significa fondamentalmente che qualsiasi soluzione compresa

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

è destinato a fallire, perché la variabile e lo script non possono coesistere nello stesso file.

La semplice soluzione che alla fine mi è venuta in mente, e ha funzionato per me, era semplicemente racchiudere la variabile con un tag con id e successivamente riferirla ad essa nel file js, in questo modo:

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

e poi:

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

e sufficiente includere <script src="static/js/somecode.js"></script>nel base.htmlcome al solito. Ovviamente si tratta solo di ottenere il contenuto. Per quanto riguarda la sicurezza, basta seguire le altre risposte.


Probabilmente vorrai usare .textContentinvece di .innerHTML, perché altrimenti anche le entità che hanno la codifica HTML faranno parte della variabile JS. Ma anche allora potrebbe non essere riprodotto 1: 1 (non ne sono sicuro).
pcworld,

Una precisazione . Uso un modo simile per acquisire i valori di campo nelle variabili (usando gli ID creati dinamicamente nel modulo) e funziona (ma solo per UNA riga di formset ). Ciò a cui non sono in grado di aggirare, è acquisire valori da tutte le righe dei campi del formset , che vengono popolati manualmente (ovvero in una tabella html usando for loop ). Come visualizzerai, le variabili dell'ultima riga del formset vengono passate alle variabili e i valori precedenti vengono sovrascritti con questi ultimi mentre il ciclo for procede attraverso le righe del formset. C'è un modo per aggirare questo?
user12379095

3

Per un oggetto JavaScript memorizzato in un campo Django come testo, che deve diventare nuovamente un oggetto JavaScript inserito in modo dinamico nello script on-page, è necessario utilizzare entrambi escapejse JSON.parse():

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

Django escapejsgestisce correttamente la quotazione e JSON.parse()converte nuovamente la stringa in un oggetto JS.


2

Si noti che se si desidera passare una variabile a uno script .js esterno, è necessario precedere il tag di script con un altro tag di script che dichiari una variabile globale.

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

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

data è definito nella vista come al solito in get_context_data

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

La parte per dichiarare una variabile a livello globale è stata effettivamente utile.
Rahul,

se si esegue il rendering dei dati in variabili js da modelli come sopra, è necessario eseguire il rendering nella stessa pagina (renderli globali) e l'altro codice va a separare il file js. Sul lato server devono essere validi i dati perché l'utente può cambiare dal browser.
Muhammad Faizan ha pagato il

1

Uso questo modo in Django 2.1 e lavoro per me e in questo modo è sicuro (riferimento) :

Lato Django:

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

Lato HTML:

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

0

puoi assemblare l'intero script in cui la tua variabile di matrice è dichiarata in una stringa, come segue,

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

che genererà una stringa come segue

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

dopo avere questa stringa, è necessario inviarlo al modello

views.py

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

nel modello lo ricevi e lo interpreti in modo letterale come codice htm, appena prima del codice javascript dove ne hai bisogno, ad esempio

modello

{{ prueba|safe  }}

e di seguito è riportato il resto del codice, tenere presente che la variabile da utilizzare nell'esempio è data2

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

in questo modo manterrai il tipo di dati, che in questo caso è un accordo


Usa questo solo se sei sicuro che aaaconterrà solo numeri, altrimenti è possibile XSS (iniezione di script).
pcworld,

0

Ci sono due cose che hanno funzionato per me in Javascript:

'{{context_variable|escapejs }}'

e altro: in views.py

from json import dumps as jdumps

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

e nel codice HTML:

{{ message|safe }}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.