Safely Using JSON with html inside of the JSON in Django Templates
Safely insert the JSON as a string, and then call JSON.parse on it
Use escapejs instead of safe. It is designed for outputting to JavaScript.
var the_json = '{{my_json|escapejs}}';
To get a JavaScript object you then need to call JSON.parse
on that string. This is always preferable than dumping a JSON-encoding into your script and evaluating it directly, for security reasons.
A useful filter to get python objects directly to the client that I use is this:
@register.filter
def to_js(value):
"""
To use a python variable in JS, we call json.dumps to serialize as JSON server-side and reconstruct using
JSON.parse. The serialized string must be escaped appropriately before dumping into the client-side code.
"""
# separators is passed to remove whitespace in output
return mark_safe('JSON.parse("%s")' % escapejs(json.dumps(value, separators=(',', ':'))))
And use it like:
var Settings = {{ js_settings|to_js }};
speedplane
Docket Alarm indexes hundreds of millions of lawsuits, analyzes what happens in them, and predicts what will happen in future cases. We package this intelligence up into a SaaS service and sell it to lawyers at top law firms. To analyze the law, we deal with lots of interesting NLP and unstructured data problems, and to tackle them, we use some of the latest machine-learning tools. We're always looking for skilled developers with a passion in the intersection of law and technology. If that's you, please get in touch.
Updated on June 18, 2022Comments
-
speedplane almost 2 years
How do you safely render JSON data in a django webapp?
On the server in django I generate JSON data and then render that JSON data in a django template. The JSON occasionally contains snippets of html. Most of the time, that's fine, however if the
</script>
tag is inside the JSON data when it is rendered, it destroys the surrounding javascript.For example...
On the server, in python I'll have this:
template_data = { 'my_json' : '[{"my_snippet": "<b>Happy HTML</b>"}]' } # pass the template data to the django template return render_to_response('my_template.html', template_data, context_instance = c)
And then in the template:
<script type="text/javascript"> var the_json = {{my_json|safe}}; </script> ... some html ...
The resulting html works fine and looks like this:
<script type="text/javascript"> var the_json = [{"my_snippet": "<b>Happy HTML</b>"}]; </script> ... some html ...
However, you run into problems when, on the server, the JSON looks like this:
template_data = { 'my_json' : '[{"my_snippet": "Bad HTML</script>"}]' } return render_to_response('my_template.html', template_data, context_instance = c)
Now, when it's rendered, you'll get:
<script type="text/javascript"> var the_json = [{"my_snippet": "Bad HTML</script>"}]; </script> ... some html ...
The closing script tag within the JSON code is treated as closing the entire script block. All of your javascript will then break.
One possible solution is to check for
</script>
when passing the template data to the template, but I feel like there is a better way. -
speedplane over 11 yearsIf you do that then
the_json
becomes a string, not a javascript json object. -
DanielB over 11 yearsYou could do
var the_json = JSON.parse({{my_json|escapejs}})
-
speedplane over 11 yearsI think you need to quote it, like this:
var the_json = JSON.parse('{{my_json|escapejs}}')
-
Flash over 11 yearsThe first line will simply get a string safely into your javascript. You then need to deserialize which is why I've created the filter. You should definitely use
JSON.parse
rather than hoping it parses as a legal object in any case. -
xolox over 8 yearsSurprisingly tricky to get this nested escaping right, I couldn't quite reason my way out of it even though I fully understood the problem. Huge thanks to Andrew for (nicely) documenting the proper way to do this!