web-dev-qa-db-fra.com

Variables de modèle Django et Javascript

Lorsque je rends une page à l'aide du rendu de modèle Django, je peux transmettre une variable de dictionnaire contenant différentes valeurs pour les manipuler dans la page à l'aide de {{ myVar }}.

Existe-t-il un moyen d'accéder à la même variable en Javascript (peut-être en utilisant le DOM, je ne sais pas comment Django rend les variables accessibles)? Je veux pouvoir rechercher des détails à l'aide d'une recherche AJAX basée sur les valeurs contenues dans les variables transmises.

166
AlMcLean

Le {{variable}} est directement substitué au HTML. Faire une vue source; ce n'est pas une "variable" ou quelque chose comme ça. C'est juste du texte rendu.

Cela dit, vous pouvez mettre ce type de substitution dans votre JavaScript.

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

Cela vous donne du javascript "dynamique".

238
S.Lott

CAUTION Vérifiez le ticket # 17419 pour discuter de l'ajout d'une balise similaire dans le noyau Django et des vulnérabilités XSS éventuelles introduites en utilisant cette balise de modèle avec les données générées par l'utilisateur. Commentaire de amacneil traite de la plupart des problèmes soulevés dans le billet.


Je pense que la manière la plus souple et la plus pratique de procéder consiste à définir un filtre de modèle pour les variables que vous souhaitez utiliser dans le code JS. Cela vous permet de vous assurer que vos données sont correctement sauvegardées et que vous pouvez les utiliser avec des structures de données complexes, telles que dict et list. C'est pourquoi j'écris cette réponse en dépit d'une réponse acceptée avec de nombreux votes positifs.

Voici un exemple de filtre de modèle:

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

Ce modèle filtre les variables en chaîne JSON. Vous pouvez l'utiliser comme ceci:

// myapp/templates/example.html

{% load js %}

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

Une solution qui a fonctionné pour moi utilise le champ de saisie masqué dans le modèle.

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

Puis obtenir la valeur en javascript de cette façon,

var myVar = document.getElementById("myVar").value;
39
bosco-

Lorsque la variable est renvoyée par Django, toutes les citations sont converties en &quot;. Utiliser {{someDjangoVariable|safe}} provoque une erreur Javascript. 

Pour résoudre ce problème, utilisez Javascript .replace:

<script type="text/javascript"> 
    var json = "{{someDjangoVariable}}".replace(/&quot;/g,"\"")
</script>
8
Jon Sakas

Pour un dictionnaire, vous devez commencer par encoder en JSON. Vous pouvez utiliser simplejson.dumps () ou, si vous souhaitez convertir un modèle de données dans App Engine, vous pouvez utiliser encode () depuis la bibliothèque GQLEncoder. 

8
jamtoday

Voici ce que je fais très facilement: J'ai modifié mon fichier base.html pour mon modèle et je l'ai mis en bas:

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

puis quand je veux utiliser une variable dans les fichiers javascript, je crée un dictionnaire DJdata et je l'ajoute au contexte avec un json: context['DJdata'] = json.dumps(DJdata)

J'espère que ça aide!

6
Alexis Parakian

Je faisais face au même problème et la réponse suggérée par S.Lott a fonctionné pour moi.

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

Toutefois, je voudrais signaler limitation majeure de mise en œuvre ici ..__ Si vous envisagez de placer votre code javascript dans un fichier différent et d'inclure ce fichier dans votre modèle. Cela ne marchera pas.

Cela ne fonctionne que lorsque votre modèle principal et le code javascript sont dans le même fichier . L'équipe de Django peut probablement résoudre cette limitation.

3
Conquistador

J'ai eu du mal avec ça aussi. En surface, il semble que les solutions ci-dessus devraient fonctionner. Cependant, l'architecture Django exige que chaque fichier HTML ait ses propres variables rendues (c'est-à-dire que {{contact}} est rendu en contact.html, alors que {{posts}} est par exemple à index.html et ainsi de suite). Par ailleurs, les balises <script> apparaissent après le {%endblock%} dans base.html duquel contact.html et index.html ont été hérités. Cela signifie essentiellement que toute solution, y compris 

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

est voué à l'échec, car la variable et le script ne peuvent pas coexister dans le même fichier. 

La solution simple que j'ai finalement trouvée et qui a fonctionné pour moi consistait simplement à envelopper la variable avec une balise avec id et à la référencer ensuite dans le fichier js, comme suit:

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

et alors:

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

et incluez simplement <script src="static/js/somecode.js"></script> dans base.html comme d'habitude . Bien sûr, il ne s'agit que de obtenir le contenu. En ce qui concerne la sécurité, suivez les autres réponses. 

2
Shoval Sadde

Depuis Django 2.1, une nouvelle balise de modèle intégrée a été introduite spécifiquement pour ce cas d'utilisation: json_script.

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

La nouvelle balise va sérialiser en toute sécurité les valeurs du modèle et protège contre XSS.

1
Jon Sakas

Notez que si vous souhaitez transmettre une variable à un script .js externe, vous devez faire précéder votre balise de script avec une autre balise de script déclarant une variable globale.

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

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

data est défini dans la vue comme d'habitude dans le get_context_data

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

Pour un objet JavaScript stocké sous forme de texte dans un champ Django, qui doit redevenir un objet JavaScript inséré de manière dynamique dans le script sur la page, vous devez utiliser escapejs et JSON.parse():

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

escapejs de Django gère correctement la citation, et JSON.parse() reconvertit la chaîne en objet JS.

0
shacker

vous pouvez assembler le script entier où votre variable de tableau est déclarée dans une chaîne, comme suit,

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

qui va générer une chaîne comme suit

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

après avoir eu cette chaîne, vous devez l'envoyer au template

views.py

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

dans le modèle, vous le recevez et interprétez-le littéralement comme un code htm, juste avant le code javascript où vous en avez besoin, par exemple

modèle

{{ prueba|safe  }}

et en dessous, le reste de votre code, gardez à l'esprit que la variable à utiliser dans l'exemple est data2

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

de cette façon, vous garderez le type de données, qui dans ce cas est un arrangement

0
Daniel Muñoz