Passing Python Data to JavaScript via Django

Viewed 90287

I'm using Django and Apache to serve webpages. My JavaScript code currently includes a data object with values to be displayed in various HTML widgets based on the user's selection from a menu of choices. I want to derive these data from a Python dictionary. I think I know how to embed the JavaScript code in the HTML, but how do I embed the data object in that script (on the fly) so the script's functions can use it?

Put another way, I want to create a JavaScript object or array from a Python dictionary, then insert that object into the JavaScript code, and then insert that JavaScript code into the HTML.

I suppose this structure (e.g., data embedded in variables in the JavaScript code) is suboptimal, but as a newbie I don't know the alternatives. I've seen write-ups of Django serialization functions, but these don't help me until I can get the data into my JavaScript code in the first place.

I'm not (yet) using a JavaScript library like jQuery.

8 Answers

As of mid-2018 the simplest approach is to use Python's JSON module, simplejson is now deprecated. Beware, that as @wilblack mentions you need to prevent Django's autoescaping either using safe filter or autoescape tag with an off option. In both cases in the view you add the contents of the dictionary to the context

viewset.py

import json
 def get_context_data(self, **kwargs):
    context['my_dictionary'] = json.dumps(self.object.mydict)

and then in the template you add as @wilblack suggested:

template.html

<script>
    my_data = {{ my_dictionary|safe }};
</script>

Security warning: json.dumps does not escape forward slashes: an attack is {'</script><script>alert(123);</script>': ''}. Same issue as in other answers. Added another answer hopefully fixing it.

Fixing the security hole in the answers by @willblack and @Daniel_Kislyuk.

If the data is untrusted, you cannot just do

viewset.py

 def get_context_data(self, **kwargs):
    context['my_dictionary'] = json.dumps(self.object.mydict)

template.html

<script>
    my_data = {{ my_dictionary|safe }};
</script>

because the data could be something like {"</script><script>alert(123);</script>":""} and forward slashes aren't escaped by default. Clearly the escaping by json.dumps may not 100% match the escaping in Javascript, which is where the problems come from.

Fixed solution

As far as I can tell, the following fixes the problem:

<script>
   my_data = JSON.parse("{{ my_dictionary|escapejs }}");
</script>

If there are still issues, please post in the comments.

Related