title: Safely Using JSON with html inside of the JSON in Django Templates
body: <p>How do you safely render JSON data in a django webapp?</p>
  
  <p>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 <code>&lt;/script&gt;</code> tag is inside the JSON data when it is rendered, it destroys the surrounding javascript.</p>
  
  <p>For example...</p>
  
  <p><strong>On the server</strong>, in python I'll have this:</p>
  
  <pre><code>template_data = {
      'my_json' : '[{"my_snippet": "&lt;b&gt;Happy HTML&lt;/b&gt;"}]'
  }
  # pass the template data to the django template
  return render_to_response('my_template.html', template_data, context_instance = c)
  </code></pre>
  
  <p>And then <strong>in the template</strong>:</p>
  
  <pre><code>&lt;script type="text/javascript"&gt;
  var the_json = {{my_json|safe}};
  &lt;/script&gt;
  ... some html ...
  </code></pre>
  
  <p>The <strong>resulting html</strong> works fine and looks like this:</p>
  
  <pre><code>&lt;script type="text/javascript"&gt;
  var the_json = [{"my_snippet": "&lt;b&gt;Happy HTML&lt;/b&gt;"}];
  &lt;/script&gt;
  ... some html ...
  </code></pre>
  
  <p>However, you run into problems when, on the server, the JSON looks like this:</p>
  
  <pre><code>template_data = {
      'my_json' : '[{"my_snippet": "Bad HTML&lt;/script&gt;"}]'
  }
  return render_to_response('my_template.html', template_data, context_instance = c)
  </code></pre>
  
  <p>Now, when it's rendered, you'll get:</p>
  
  <pre><code>&lt;script type="text/javascript"&gt;
  var the_json = [{"my_snippet": "Bad HTML&lt;/script&gt;"}];
  &lt;/script&gt;
  ... some html ...
  </code></pre>
  
  <p>The closing script tag within the JSON code is treated as closing the entire script block. All of your javascript will then break.</p>
  
  <p>One possible solution is to check for <code>&lt;/script&gt;</code> when passing the template data to the template, but I feel like there is a better way.</p>