我正在使用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 }}
?
答案 0 :(得分:7)
bar = json.dumps(foo, ensure_ascii=False)
会导致bar
成为unicode
个对象;如果没有ensure_ascii=False,则bar
为str
。
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 }}