将 JSON 数组从 Django 视图返回到模板

IT技术 javascript python django json
2021-03-12 04:18:32

我正在使用 Django 为项目创建基于 Web 的应用程序,但在将数组从 Django 视图返回到模板时遇到了问题。

JavaScript (JQuery) 脚本将使用该数组在页面中显示的图像上绘制框。因此,该数组将包含要绘制的框的坐标。

这是 Django 视图中用于获取所需数据并将其序列化为 JSON 的代码:

def annotate(request, ...):
    ...
    oldAnnotations = lastFrame.videoannotation_set.filter(ParentVideoLabel=label)
    tags = serializers.serialize("json", oldAnnotations)
    ...
    return render_to_response('vannotate.html', {'tags': tags, ...})

作为调试的一种方式,{{ tags }}在模板的 HTML 部分中使用将其作为输出(对不起,很长的一行):

[{"pk": 491, "model": "va.videoannotation", "fields": {"ParentVideoFile": 4, "ParentVideoFrame": 201, "ParentVideoLabel": 4, "top": 220, "height": 30, "width": 30, "ParentVideoSequence": 16, "left": 242}}, {"pk": 492, "model": "va.videoannotation", "fields": {"ParentVideoFile": 4, "ParentVideoFrame": 201, "ParentVideoLabel": 4, "top": 218, "height": 30, "width": 30, "ParentVideoSequence": 16, "left": 307}}]

我认为这是 JSON 数组的正确格式。

稍后在模板中,我尝试实际使用tags模板的 JavaScript 部分中的变量,如下所示:

{% if tags %}
  var tagbs = {{ tags|safe }};
  var tgs = JSON.parse(tagbs);
  alert("done");
{% endif %}

如果我删除该var tgs = JSON.parse(tagbs);行,则警告框会正常弹出,其余的 JavaScript 会按预期工作。但是,保留这一行会破坏脚本。

我希望能够遍历 Django 模型中的所有对象并获取 JavaScript 中的字段值。

我不确定我在这里做错了什么,有人可以指出正确的方法吗?

3个回答

使用 Django 2.1+ 和现代网络的更新进行编辑:

现代方法是:

1) 将原始数据传递给模板,而不是 JSON 序列化的数据。IE:

def annotate(request, ...):
    ...
    oldAnnotations = lastFrame.videoannotation_set.filter(ParentVideoLabel=label)
    ...
    return render_to_response('vannotate.html', {'tags': oldAnnotations, ...})

2) 在您的模板中,使用新的“json_script”过滤器来包含 JSON 数据:

{{ tags|json_script:"tags-data" }}

这将导致 HTML 如下所示:

<script id="tags-data" type="application/json">{"foo": "bar"}</script>

该标签对包含“</script>”的字符串进行了特殊处理,以确保它们正常工作。

3) 在你的 Javascript 代码中,像这样获取标签数据:

var tags = JSON.parse(document.getElementById('tags-data').textContent);

4) 将您的 Javascript 代码移至外部 .js 文件,并设置 Content-Security-Policy 标头以禁止内联 Javascript,因为它存在安全风险。请注意,由于 json_script 标记生成 JSON,而不是 Javascript,因此无论您的 Content-Security-Policy 设置如何,它都是安全的并且是允许的。

原答案:

警告:如果任何字符串是用户控制的,这是不安全的

JSONJavascript 源代码。即数组的 JSON 表示是定义数组所需的 Javascript 源代码。

所以之后:

var tagbs = {{ tags|safe }};

tagbs是一个包含所需数据的 JavaScript 数组。无需调用 JSON.parse(),因为 Web 浏览器已将其解析为 JavaScript 源代码。

所以你应该能够做到

var tagbs = {{ tags|safe }};
alert(tagbs[0].fields.ParentVideoFile);

那应该显示“4”。

警告:使用这种旧方法,包含“</script>”的字符串将不起作用,它们会出错。这是因为浏览器会将 </script> 视为脚本的结尾。如果任何字符串是用户输入的数据,则这是一个可利用的安全漏洞 -有关更多详细信息,请参阅此处的评论 14改用上面更现代的方法。

伙计,我喜欢 StackOverflow。那个小修复解决了一切!我是新手,我认为 JSON.parse 是将 JSON 变量解析为数组,而不是相反。谢谢一堆!
2021-04-25 04:18:32
|safe意味着 Django 不应该尝试对它进行 HTML 转义 - 它已经是安全的。没有它,Django 将替换"&quot;并且它会崩溃。
2021-04-26 04:18:32
你不应该|safe在这里使用仅用于 HTML 清理所需。JSON已经使这个安全的JavaScript,HTML的任何内容应该被转义。
2021-04-29 04:18:32
@Mike:请注意,在问题中,“标签”已经包含 JSON(即它是serializers.serialize("json", ...)or的输出json.dumps(...))。我认为你正在传递一个原始的 Python 数组,它不起作用。尝试json.dumps(...)在您的 Python 代码中执行并传递它。如果这不起作用,请尝试创建一个单独的新问题。
2021-05-06 04:18:32
如果 JSON 表示包含“</script>”,例如var tagbs = {"k": 12, "p": "</script>"};.
2021-05-08 04:18:32

您想对模板中的数据进行 JSON 化JSON 已经是真正的 Javascript(它是一个子集:

{% if tags %}
  var tgs = {{ tags }};
{% endif %}

请注意,tags已经是JSON(JavaScript的因而)数据和可以插入直接; 无需转义(此处没有 HTML,而是 JavaScript)。

或者您可以使用此Django 代码段并直接在模板中执行(无需调用serializers.serializeannotate方法):

var tgs = {{ tags|jsonify }};
@user2203255:把它放在旁边的一个新的templatetags子包(一个包含__init__.py文件的目录)中,参见docs.djangoproject.com/en/dev/howto/custom-template-tagsmodels.pyviews.py
2021-04-25 04:18:32
我不得不 JSON.parse 返回的 jsonified 字符串: var packet_json={{the_packet|jsonify|safe}}; 警报(packet_json);var tgs = JSON.parse(packet_json); for (e in tgs['results']) { alert("First: "+e); }
2021-04-26 04:18:32
太好了,这也有效!它确实简化了以后的事情。不过有一件事。我必须向safe(即{{ tags|jsonify|safe }}添加一个额外的管道才能使其工作。也许这与我的对象本身有关。
2021-05-10 04:18:32
我应该将jsonify过滤器定义放在views文件中吗?我尝试按照链接上的说明进行操作,但 Django 告诉我jsonify过滤器无效。
2021-05-12 04:18:32
@jonincanada:JSON是 JavaScript 的一个子集;你不应该解析它,它可以直接使用。
2021-05-16 04:18:32

您也可以使用simplejson来自django.utils. 喜欢:

oldAnnotations = lastFrame.videoannotation_set.filter(ParentVideoLabel=label)
dump = simplejson.dumps(oldAnnotations)

return HttpResponse(dump, mimetype='application/json')

您可以从 JS 端解析和访问此中的所有数据。

这在Django 1.5 中已被弃用
2021-05-01 04:18:32