310

When I render a page using the Django template renderer, I can pass in a dictionary variable containing various values to manipulate them in the page using {{ myVar }}.

Is there a way to access the same variable in Javascript, <script></script> (perhaps using the DOM, I don't know how Django makes the variables accessible)? I want to be able to lookup details using an AJAX lookup based on the values contained in the variables passed in.

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
AlMcLean
  • 3,459
  • 2
  • 19
  • 14

19 Answers19

392

The {{variable}} is substituted directly into the HTML. Do a view source; it isn't a "variable" or anything like it. It's just rendered text.

Having said that, you can put this kind of substitution into your JavaScript.

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

This gives you "dynamic" javascript.

Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • 45
    Note though that according to [this solution](http://stackoverflow.com/questions/298772/django-template-variables-and-javascript/1187881#1187881), this is vulnerable to injection attacks – Casebash Jun 13 '10 at 06:13
  • 18
    @Casebash: For such occasions `escapejs` filter exists: `escapejs('<>') -> u'\\u003C\\u003E'` – Tomasz Zieliński Aug 23 '11 at 10:54
  • 35
    Just to add on to this for reference: if the "someDjangoVariable" so happens to be JSON, be sure to use {{ someDjangoVariable|safe }} to remove the " – Mark Feb 07 '12 at 14:39
  • 1
    Additionally make sure that the string isn't broken into multiple lines. – Mikhail Feb 21 '13 at 00:48
  • Does anyone know of a "gon" (https://github.com/gazay/gon) equivalent for Django? – Mario Oct 20 '14 at 03:42
  • 4
    This answer only works for a simple variable, it does not work for a complex data structure. In this case, the simplest solution is to add client-side code to traverse the data structure and build a similar one in Javascript. If the complex data structure is in JSON format, another solution is to serialize it, pass a serialized JSON to the Django template in server-side code and deserialize the JSON in a javascript object in client-side code. One answer below mentions this alternative. – Alan Evangelista Nov 20 '14 at 19:15
  • 2
    Please update this to include the |escapejs filter, otherwise you can end up with variables containing quote characters in the name and such, and this can lead to XSS attacks. – w0rp Apr 30 '15 at 10:07
  • 2
    So the best solution is to use `var a = {{someDjangoVariable|escapejs|safe}}"` then? – user1496984 May 29 '15 at 04:48
  • 26
    what if the javascript is written in a different file? – the_unknown_spirit Nov 15 '16 at 07:05
  • 13
    10 years later and Django has introduced a built in template filter just for this: https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#json-script – Jon Sakas Jan 19 '19 at 19:55
  • 1
    I have Django template for creating a button with id in html tag = name of the object `id="{{ obj.name }}`. Now how to refer to this id by JS? Doing this is giving me error. `var c = document.getElementById({{ obj.name }});` – Mohith7548 Jun 28 '19 at 14:26
  • If you have double quotes or single quotes in your ```someDjangoVariable```, it's better to do this ```var a = `{{someDjangoVariable|safe}}`;```. Or if it's JSON content in your ```someDjangoVariable```, it's might be best to just do ```var a = {{someDjangoVariable|safe}};```, this way Javascript will load the JSON correctly – Yi Zong Kuang Jan 19 '22 at 18:47
89

CAUTION Check ticket #17419 for discussion on adding similar tag into Django core and possible XSS vulnerabilities introduced by using this template tag with user generated data. Comment from amacneil discusses most of the concerns raised in the ticket.


I think the most flexible and handy way of doing this is to define a template filter for variables you want to use in JS code. This allows you to ensure, that your data is properly escaped and you can use it with complex data structures, such as dict and list. That's why I write this answer despite there is an accepted answer with a lot of upvotes.

Here is an example of template filter:

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

This template filters converts variable to JSON string. You can use it like so:

// myapp/templates/example.html

{% load js %}

<script type="text/javascript">
    var someVar = {{ some_var | js }};
</script>
Yaroslav Admin
  • 13,880
  • 6
  • 63
  • 83
  • 4
    That is nice because it allows copying only some Django template input variables to Javascript and server-side code does not need to know which data structures must be used by Javascript and hence converted to JSON before rendering the Django template. Either use this or always copy all Django variables to Javascript. – Alan Evangelista Nov 20 '14 at 19:22
  • But note: http://stackoverflow.com/questions/23752156/are-all-json-objects-also-valid-javascript-objects – Ciro Santilli OurBigBook.com Jun 03 '16 at 14:12
  • Nice. Is that the same as just using https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#safe though? – Jorge Orpinel Pérez May 30 '17 at 03:38
  • 2
    @JorgeOrpinel No, it is not same. `safe` only marks value as safe, without proper conversion and escaping. – Yaroslav Admin May 30 '17 at 10:52
  • 2
    How do you then display the variable in the django template? – kbdev Jun 14 '17 at 17:33
  • Please can anyone tell me how would you access that variable in an external JavaScript file ? but a secure way. – Ahtisham Dec 21 '17 at 12:51
  • @YaroslavAdmin, isn't it a problem that this solutions requires one to always keep the javascript in the template file? Most of the projects I've seen keeps the javascript in a separate js-folder. I tried you solution and it doesn't work with the js in a separate folder. – Sahand Dec 21 '17 at 16:46
  • 1
    @Sandi back when I posted it it was common to have a widget in separate JS file and initialize it in the page source code. So let's say you declare `function myWidget(config) { /* implementation */ }` in JS file and than you use it on some pages using `myWidget({{ pythonConfig | js }})`. But you can not use it in JS files (as you noticed), so it has its limitations. – Yaroslav Admin Dec 21 '17 at 16:55
  • Don't use this, it's vulnerable to XSS (script injection). For instance an attacker could inject `` into the data, thus breaking out of the current script and injecting arbitrary HTML (including starting a new script with ` – pcworld Aug 29 '19 at 14:38
78

A solution that worked for me is using the hidden input field in the template

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

Then getting the value in javascript this way,

var myVar = document.getElementById("myVar").value;
bosco-
  • 1,733
  • 2
  • 15
  • 18
  • 3
    be wary though. depending on how you use the variable/form, the user could put in whatever they want. – AndyL May 02 '12 at 23:24
  • 4
    you may also want to set your input field to readonly (see this link http://www.w3schools.com/tags/att_input_readonly.asp) – nu everest Dec 20 '12 at 13:53
  • If it's something that won't alter a database or won't be sent to a database query this would be fine. @AndyL – James111 Feb 08 '16 at 22:18
  • 9
    Guys... users can do what they want anyways. Browsers make it so easy nowadays with a fully featured DOM inspector and debugging tools. Moral of the story: do ALL you data validation on the **server**. – user2867288 Feb 18 '17 at 07:14
  • 1
    Please can anyone tell me how would you access that variable in an external JavaScript file ? – Ahtisham Dec 21 '17 at 12:54
  • Ahtisham, you get it by doing what bosco- did: `var myVar = document.getElementById("myVar").value;`. This will work if the javascript is executed on the same page as the hidden input element. – Sahand Dec 21 '17 at 14:57
57

As of Django 2.1, a new built in template tag has been introduced specifically for this use case: json_script.

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

The new tag will safely serialize template values and protects against XSS.

Django docs excerpt:

Safely outputs a Python object as JSON, wrapped in a tag, ready for use with JavaScript.

djvg
  • 11,722
  • 5
  • 72
  • 103
Jon Sakas
  • 2,042
  • 1
  • 21
  • 26
20

new docs says use {{ mydata|json_script:"mydata" }} to prevent code injection.

a good exmple is given here:

{{ mydata|json_script:"mydata" }}
<script>
    const mydata = JSON.parse(document.getElementById('mydata').textContent);
</script>
Shahriar.M
  • 818
  • 1
  • 11
  • 24
18

There is a nice easy way implemented from Django 2.1+ using a built in template tag json_script. A quick example would be:

Declare your variable in your template:

{{ variable|json_script:'name' }}

And then call the variable in your <script> Javascript:

var js_variable = JSON.parse(document.getElementById('name').textContent);

It is possible that for more complex variables like 'User' you may get an error like "Object of type User is not JSON serializable" using Django's built in serializer. In this case you could make use of the Django Rest Framework to allow for more complex variables.

Josh
  • 2,122
  • 1
  • 21
  • 28
12

For a JavaScript object stored in a Django field as text, which needs to again become a JavaScript object dynamically inserted into on-page script, you need to use both escapejs and JSON.parse():

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

Django's escapejs handles the quoting properly, and JSON.parse() converts the string back into a JS object.

shacker
  • 14,712
  • 8
  • 89
  • 89
10

Here is what I'm doing very easily: I modified my base.html file for my template and put that at the bottom:

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

then when I want to use a variable in the javascript files, I create a DJdata dictionary and I add it to the context by a json : context['DJdata'] = json.dumps(DJdata)

Hope it helps!

Insomniak
  • 443
  • 6
  • 19
9

For a dictionary, you're best of encoding to JSON first. You can use simplejson.dumps() or if you want to convert from a data model in App Engine, you could use encode() from the GQLEncoder library.

JJ.
  • 4,974
  • 5
  • 39
  • 48
7

Note, that if you want to pass a variable to an external .js script then you need to precede your script tag with another script tag that declares a global variable.

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

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

data is defined in the view as usual in the get_context_data

def get_context_data(self, *args, **kwargs):
    context['myVar'] = True
    return context
Daniel Kislyuk
  • 956
  • 10
  • 11
  • The part to declare a variable globally was actually helpful. – Rahul May 29 '20 at 23:22
  • if you render data into js variables from templates like above then must render into same page (make them global) and other code goes to separate js file. On server side must valid data because user can change from browser. – Muhammad Faizan Fareed Jun 14 '20 at 12:53
6

I was facing simillar issue and answer suggested by S.Lott worked for me.

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

However I would like to point out major implementation limitation here. If you are planning to put your javascript code in different file and include that file in your template. This won't work.

This works only when you main template and javascript code is in same file. Probably django team can address this limitation.

Conquistador
  • 121
  • 4
  • 10
5

I've been struggling with this too. On the surface it seems that the above solutions should work. However, the django architecture requires that each html file has its own rendered variables (that is, {{contact}} is rendered to contact.html, while {{posts}} goes to e.g. index.html and so on). On the other hand, <script> tags appear after the {%endblock%} in base.html from which contact.html and index.html inherit. This basically means that any solution including

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

is bound to fail, because the variable and the script cannot co-exist in the same file.

The simple solution I eventually came up with, and worked for me, was to simply wrap the variable with a tag with id and later refer to it in the js file, like so:

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

and then:

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

and just include <script src="static/js/somecode.js"></script> in base.html as usual. Of course this is only about getting the content. Regarding security, just follow the other answers.

Shoval Sadde
  • 1,152
  • 1
  • 11
  • 11
  • You probably want to use `.textContent` instead of `.innerHTML`, because otherwise entities that get HTML-encoded will be part of the JS variable too. But even then it might not be reproduced 1:1 (I'm not sure). – pcworld Aug 29 '19 at 15:11
  • **A clarification**. I use a similar way to capture field values in variables (using IDs dynamically created in the form), and it's working (but for only **ONE formset row**). What I am not able to get around to, is **to capture values from all the rows of formset fields**, which are being populated manually (i.e. in an html table using **for loop**). As you will visualize the variables of only the last formset row is passed to the variables, and the values before that are overwritten with the latter values as the for loop progresses through the formset rows. **Is there a way around to this?** – Love Putin Not War Apr 25 '20 at 14:09
5

I have found we can pass Django variables to javascript functions like this:-

<button type="button" onclick="myJavascriptFunction('{{ my_django_variable }}')"></button>
<script>
    myJavascriptFunction(djangoVariable){
       alert(djangoVariable);
    }
</script>
Devesh Pradhan
  • 149
  • 1
  • 6
4

I use this way in Django 2.1 and work for me and this way is secure (reference):

Django side:

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

Html side:

<script type='text/javascript'>
     const  mydata = {{ mydata_json|safe }};
console.log(mydata)
 </script>
henrry
  • 486
  • 6
  • 25
  • I think you misunderstood the reference article that you gave. It is clearly showing that using 'json.dumps' and ' | safe' together is also a vulnerable way. Read the paragraph below "Another Vulnerable Way" headline. – yuv Jun 08 '21 at 12:48
  • where is it paragraph "Another Vulnerable Way" ? – henrry Aug 12 '21 at 06:44
1

There are two things that worked for me inside Javascript:

'{{context_variable|escapejs }}'

and other: In views.py

from json import dumps as jdumps

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

and in the html:

{{ message|safe }}
nofoobar
  • 2,826
  • 20
  • 24
1

You can use the variables from views.py in JavaScript, <script></script> in Django Templates.

For example, if you pass the dictionary with persons having a list of dictionaries from views.py to Django Templates as shown below:

# "views.py"

from django.shortcuts import render

def test(request, id=None, slug=None):
    persons = [
        {'name':'John', 'age':36},
        {'name':'David','age':24}
    ]
    return render(request, 'index.html', {"persons":persons})

Then, you can use the variables in JavaScript, <script></script> in Django Templates as shown below:

# "index.html"

<script>
{% for person in persons %}
    console.log("{{ person.name }} {{ person.age}}");
{% endfor %}
</script>

Then, these results are displayed on console:

John 36
David 24

Be careful, if you use a JavaScript's variable and for loop, unexpected results are displayed on console:

# "index.html"

<script>
let js_persons = "{{ persons }}"
for (let i = 0; i < js_persons.length; i++) {
    console.log(js_persons[i]);
}
</script>

Of course, you can use comment tag in JavaScript, <script></script> in Django Templates as shown below:

# "index.html"

<script>
{% for person in persons %}
    {% comment %} 
    console.log("{{ person.name }} {{ person.age}}"); 
    {% endcomment %}
{% endfor %}
</script>
# "index.html"

<script>
{% comment %}
{% for person in persons %}
    console.log("{{ person.name }} {{ person.age}}"); 
{% endfor %}
{% endcomment %}
</script>
# "index.html"

{% comment %}
<script>
{% for person in persons %}
    console.log("{{ person.name }} {{ person.age}}"); 
{% endfor %}
</script>
{% endcomment %}
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
0

you can assemble the entire script where your array variable is declared in a string, as follows,

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

that will generate a string as follows

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

after having this string, you must send it to the template

views.py

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

in the template you receive it and interpret it in a literary way as htm code, just before the javascript code where you need it, for example

template

{{ prueba|safe  }}

and below that is the rest of your code, keep in mind that the variable to use in the example is data2

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

that way you will keep the type of data, which in this case is an arrangement

Daniel Muñoz
  • 547
  • 1
  • 7
  • 23
  • Use this only if you're sure that `aaa` will only contain numbers, otherwise XSS (script injection) is possible. – pcworld Aug 29 '19 at 14:47
0

There are various answers pointing to json_script. Contrary to what one might think, that's not a one size fits all solution.

For example, when we want to pass to JavaScript dynamic variables generated inside a for loop, it's best to use something like data-attributes.

See it in more detail here.

Tiago Martins Peres
  • 14,289
  • 18
  • 86
  • 145
0

If you want to send variable directly to a function by passing it as a parameter then try this

<input type="text" onkeyup="somefunction('{{ YOUR_VARIABLE }}')">

As from previous answers the security can be improved upon

DragonFire
  • 3,722
  • 2
  • 38
  • 51