Django模板上的Unicode字符串显示

时间:2013-12-30 05:21:25

标签: python django json unicode

我正在使用django v1.5。*,我将渲染一个名为“foobar”的变量,它是一个json obj并包含unicode字符串。

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

在我的模板中,我在javascript中编码json obj,然后追加到div,它可以显示预期的字符串:

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

然后我可以在我的网页上获得赞一下我们 但我发现如果我直接使用变量:

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

它会将unicode字符串显示为字节字符串:
{ "name":"\u8d5e\u4e00\u4e0b\u6211\u4eec" }
即使我使用{{foobar|safe}},也没有任何改变。

现在,我想问为什么会发生这种情况或者我有什么不对劲?如果我想直接将变量用作{{ foobar }}

,我该怎么办?

3 个答案:

答案 0 :(得分:7)

bar = json.dumps(foo, ensure_ascii=False)会导致bar成为unicode个对象;如果没有ensure_ascii=False,则barstr

Django的smart_text方法对转换也很有用。

答案 1 :(得分:2)

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

将unicode字符串显示为字节字符串:{ "name":"\u8d5e\u4e00\u4e0b\u6211\u4eec" }

这是以JSON编码的形式显示整个对象。虽然您可以使用json.dumps(..., ensure_ascii=False)以非原始形式保存非ASCII字符(如中文)而不是编码为ASCII-safe-JSON,但这仍然会给您{"name": "赞一下我们"}这可能不是您想要的。

如果您只想要包含在div中的对象的name属性,则需要将项foo['name']传递给您的模板 - 或整个foo并拥有模板包含{{foo.name}} - 而不是包含foobar中的整个编码JSON对象。

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

ECMA标准encode对象上没有方法JSON,因此我不知道它在做什么。

JSON编码方法是JSON.stringify。但是你不想在这里进行编码 - 你已经有了一个带有对象的JSON表示的字符串,因为你在调用json.dumps时在服务器端编写了它。可能你的意思是:

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

适用于name的特定值,但不一定是一般的。例如,如果名称为a\nb,那么您将得到:

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

在这种情况下,\n将被JavaScript解释器解析为字符串中的换行符,因此解析为JSON的字符串将是:

{"name": "a
b"}

这是一个语法错误。这里也存在安全问题 - 与|safe断言相反,这是不安全的。如果name属性包含字符串</script,那么您最终会得到一个过早结束的脚本元素,这会导致跨站点脚本攻击:

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

您可以尝试通过在服务器端对JSON执行第二层JS字符串文字编码来解决这些问题,并使用<手动替换\u003C。但是最好采用不同的方法 - 动态生成可执行代码通常会遇到问题,特别是当你在混合中有多种不同的语法时(Python / Django-template,HTML和JS / JSON)。

如果您将数据写入文档(例如,在data-属性中)而不是脚本,那么您可以保持HTML转义的正常和安全模板行为。然后JS方可以从DOM中读取数据。例如:

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

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

(jQuery的data方法隐含地为你做JSON.parse。)

这有助于分离关注点,将JS放入外部脚本,并最终使用Content-Security-Policy。

答案 2 :(得分:1)

您需要引用dict中的元素,而不对其进行JSON编码。

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

...

{{ foo.name }}