3

I am using django v1.5.*, I am going to render the a variable named "foobar" which is a json obj and including unicode string.

def home( request ):
    import json
    foo = {"name": u"赞我们一下"}
    bar = json.dumps( foo )
    return render_to_response( 'myapp/home.html',
        { "foobar": bar, },
        context_instance=RequestContext(request)
    )

And in my template, I encode the json obj in javascript and then append to the div, it can display the expected string:

  foobar=JSON.encode('{{foobar|safe}}'); 
  $("#foobar").html(foobar.name);`

then I can get the 赞一下我们 on my web page.
But I found that if I use the variable directly:

<div id="foobar">{{ foobar }}</div>

it will display the unicode string as byte string:
{ "name":"\u8d5e\u4e00\u4e0b\u6211\u4eec" }
Even if I using the {{foobar|safe}} then nothing change.

Now, I want to ask why this happend or is anything wrong of me? What should I do if I do want to using the variable directly as {{ foobar }} ?

3 Answers 3

7

bar = json.dumps(foo, ensure_ascii=False) will result in bar being a unicode object; without ensure_ascii=False, bar is a str.

Django's smart_text method might also be useful for conversions.

Sign up to request clarification or add additional context in comments.

1 Comment

Thx! That what I need. & Your reference URLs also give me good explanation as well!! All can find in the official website, it's no doubt that I should read the document more carefully than before.
4
<div id="foobar">{{ foobar }}</div>

will display the unicode string as byte string: { "name":"\u8d5e\u4e00\u4e0b\u6211\u4eec" }

This is displaying the whole object in its JSON-encoded form. Whilst you could use json.dumps(..., ensure_ascii=False) to keep non-ASCII characters like the Chinese in their raw form rather than encoded into ASCII-safe-JSON, this would still give you {"name": "赞一下我们"} which is probably not what you want.

If you only want the name property of the object included in the div, you will need to pass the item foo['name'] to your template - or the whole of foo and have the template include {{foo.name}} - rather than including the whole encoded JSON object from foobar.

foobar=JSON.encode('{{foobar|safe}}'); 

There is no method encode on the ECMA standard JSON object, so I don't know what that's doing.

The JSON-encoding method is JSON.stringify. But you don't want to encode here - you already have a string with a JSON representation of an object here because you encoded it above at the server side in the call to json.dumps. Probably you meant:

var foobar = JSON.parse('{{foobar|safe}}'); 

which would work for your particular value of name, but not necessarily in general. For example if the name was a\nb then you would get:

JSON.parse('{"name": "a\nb"}')

in which case the \n would get parsed by the JavaScript interpreter as being a newline character in the string, and so the string parsed as JSON would be:

{"name": "a
b"}

which is a syntax error. There are also security issues here - contrary to the |safe assertion, this is not safe. If the name property contained the string </script then you would end up with a prematurely-ended script element, which can lead to cross-site scripting attacks:

<script>
var foobar = JSON.parse('</script>
<script>alert();//attacker code here');</script>

You could attempt to get around these by doing a second layer of JS string literal encoding on the JSON at the server side, and manually replace < with \u003C. But probably it's best to take a different approach - generating executable code on the fly is fraught with problems in general, especially when you have multiple different syntaxes in the mix (Python/Django-template, HTML and JS/JSON).

If you write data to the document (for example in a data- attribute) rather than the script then you can keep the normal and safe template behaviour of HTML-escaping. Then the JS side can read the data out of the DOM. For example:

<div id="foobar" data-foobar="{{ foobar }}">
...

var foobar = $('#foobar').data('foobar');

(jQuery's data method implicitly does the JSON.parse for you.)

This helps with separation of concerns, getting JS out into external scripts, and potentially eventually using Content-Security-Policy.

Comments

1

You need to reference the element within the dict, without JSON-encoding it.

return render_to_response(..., {..., 'foo': foo}, ...)

...

{{ foo.name }}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.