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

Posted

技术标签:

【中文标题】将 JSON 数组从 Django 视图返回到模板【英文标题】:Returning JSON array from a Django view to a template 【发布时间】:2013-03-13 15:15:44 【问题描述】:

我正在使用 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, ...)

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

["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 数组的正确格式。

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

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

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

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

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

【问题讨论】:

您没有将数据发送到 JavaScript,而是在服务器端注入脚本,因此代码在客户端被解释为 JavaScript。如果您查看源代码,您会发现它是一个普通的数组文字。在这种情况下它不是 JSON,所以你无法解析它。 【参考方案1】:

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

现代的做法是:

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

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>

此标记对包含“”的字符串进行特殊处理,以确保它们正常工作。

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 设置如何都是允许的。

原答案:

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

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

那么之后:

var tagbs =  tags|safe ;

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

所以你应该可以做到

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

应该显示“4”。

警告:使用这种旧方法,包含“”的字符串将不起作用,它们会出错。这是因为浏览器会将 视为脚本的结尾。如果任何字符串是用户输入的数据,这是一个可利用的安全漏洞 - see comment 14 here for more details。请改用上述更现代的方法。

【讨论】:

伙计,我喜欢 ***。那个小修复解决了一切!我是新手,我认为 JSON.parse 是将 JSON 变量解析为数组,而不是相反。非常感谢! 你不应该在这里使用|safe;这仅在 HTML 清理时需要。 JSON 已经使​​这个 JavaScript 安全,任何 HTML 内容都应该被转义。 |safe 意味着 Django 不应该尝试对它进行 HTML 转义——它已经是安全的了。没有它,Django 会将" 替换为&amp;quot; 并且它会中断。 @Mike:请注意,在问题中,“标签”已经包含 JSON(即,它是 serializers.serialize("json", ...)json.dumps(...) 的输出)。我认为您正在传递一个原始 Python 数组,这将不起作用。尝试在您的 Python 代码中执行 json.dumps(...) 并传递它。如果这不起作用,请尝试创建一个单独的新问题。 如果 JSON 表示包含“”,这可能会导致 JS 语法无效,例如 var tagbs = "k": 12, "p": "&lt;/script&gt;";【参考方案2】:

您也可以使用django.utils 中的simplejson。喜欢:

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

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

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

【讨论】:

在Django 1.5中已弃用【参考方案3】:

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

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

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

或者您可以使用这个Django snippet 并直接在模板中执行(无需在annotate 方法中调用serializers.serialize):

var tgs =  tags|jsonify ;

【讨论】:

我应该将jsonify 过滤器定义放在views 文件中吗?我尝试按照链接上的说明进行操作,但 Django 告诉我 jsonify 过滤器无效。 @user2203255:把它放在你的models.pyviews.py旁边的一个新的templatetags子包(带有__init__.py文件的目录)中,见docs.djangoproject.com/en/dev/howto/custom-template-tags 太好了,这也有效!它确实简化了以后的事情。不过有一件事。我必须向safe(即 tags|jsonify|safe )添加一个额外的管道才能使其工作。也许这与我的对象本身有关。 我不得不 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); @jonincanada: JSON 是 JavaScript 的一个子集;不用解析,直接使用即可。

以上是关于将 JSON 数组从 Django 视图返回到模板的主要内容,如果未能解决你的问题,请参考以下文章

Django 使用自定义 SQL 而不是模型将 JSON 对象返回到模板

从 django 模板中转义 JSON 数据的正确方法

将对象从模板传递给 django 视图(控制器)

无法将参数从模板传递到 Django 视图

Django - 将变量从函数视图传递到 html 模板

Django - 将变量从基于类的视图传递到模板