通过Django将Python数据传递给JavaScript

时间:2009-09-18 17:52:53

标签: javascript python django

我正在使用Django和Apache来提供网页服务。我的JavaScript代码目前包含一个数据对象,其值根据用户从选项菜单中的选择显示在各种HTML小部件中。我想从Python字典中获取这些数据。我想我知道如何在HTML中嵌入JavaScript代码,但是如何在该脚本中嵌入数据对象(动态),以便脚本的功能可以使用它?

换句话说,我想从Python字典创建一个JavaScript对象或数组,然后将该对象插入到JavaScript代码中,然后将该JavaScript代码插入到HTML中。

我认为这种结构(例如,嵌入在JavaScript代码中的变量中的数据)不是最理想的,但作为一个新手,我不知道其他选择。我已经看过Django序列化函数的编写,但是这些对我来说没有帮助,直到我可以将数据放到我的JavaScript代码中。

我还没有使用像jQuery这样的JavaScript库。

7 个答案:

答案 0 :(得分:78)

n.b。见底部的2018更新

我建议不要在Django模板中加入大量JavaScript - 它往往很难编写和调试,特别是在项目扩展时。相反,尝试将所有JavaScript编写在模板加载的单独脚本文件中,只需在模板中包含一个JSON数据对象。这允许您执行诸如JSLint之类的操作来运行整个JavaScript应用程序,缩小它等等。您可以使用静态HTML文件对其进行测试,而不依赖于您的Django应用程序。使用像simplejson这样的库也可以节省编写繁琐的序列化代码所花费的时间。

如果你不假设你正在构建一个AJAX应用程序,这可能只是这样做:

在视图中:

from django.utils import simplejson


def view(request, …):
    js_data = simplejson.dumps(my_dict)
    …
    render_template_to_response("my_template.html", {"my_data": js_data, …})

在模板中:

<script type="text/javascript">
    data_from_django = {{ my_data }};
    widget.init(data_from_django);
</script>

请注意,数据类型很重要:如果my_data是简单数字或来自受控源的字符串(不包含HTML),例如格式化日期,则无需进行特殊处理。如果用户可能提供不受信任的数据,则需要使用escapeescapejs过滤器对其进行清理,并确保JavaScript安全处理数据以避免cross-site scripting次攻击。

就日期而言,您可能还想考虑如何传递日期。我几乎总是发现将它们作为Unix时间戳传递最简单:

在Django中:

time_t = time.mktime(my_date.timetuple())

在JavaScript中,假设您使用上面代码段的结果执行了time_t = {{ time_t }}之类的操作:

my_date = new Date();
my_date.setTime(time_t*1000);

最后,请注意UTC - 您希望让Python和Django日期函数以UTC格式交换数据,以避免因用户当地时间而发生令人尴尬的转变。

编辑:请注意,javascript中的setTime以毫秒为单位,而time.mktime的输出为秒。这就是为什么我们需要乘以1000

2018年更新:我仍然喜欢JSON的复杂值,但在此期间the HTML5 data API已达到near universal browser support并且传递简单(非列表/字典)值非常方便,特别是如果你可能希望根据这些值应用CSS规则,而您不关心不受支持的Internet Explorer版本。

<div id="my-widget" data-view-mode="tabular">…</div>

let myWidget = document.getElementById("my-widget");
console.log(myWidget.dataset.viewMode); // Prints tabular
somethingElse.addEventListener('click', evt => {
    myWidget.dataset.viewMode = "list";
});

如果要在Django模板中设置初始视图状态并在JavaScript更新data-属性时自动更新,这是向CSS公开数据的一种巧妙方法。我将此用于隐藏进度窗口小部件,直到用户选择要处理的内容或根据获取结果有条件地显示/隐藏错误,甚至使用像#some-element::after { content: attr(data-active-transfers); }这样的CSS显示活动记录计数。

答案 1 :(得分:38)

对于可能遇到此问题的任何人,请确保在模板中以安全模式呈现json对象。您可以像这样手动设置

<script type="text/javascript">
    data_from_django = {{ my_data|safe }};
    widget.init(data_from_django);
</script>

答案 2 :(得分:3)

您可以在.html模板中包含<script>标记,然后构建您的数据结构,但对您来说很方便。模板语言不仅适用于HTML,还可以执行Javascript对象文字。

Paul是对的:最好使用json模块创建JSON字符串,然后将该字符串插入模板中。这将最好地处理引用问题,并轻松处理深层结构。

答案 3 :(得分:2)

不是最理想的。您是否考虑过使用django内置的串行器将数据作为JSON传递?

答案 4 :(得分:1)

查看对this question的相关回复。一种选择是使用jsonpickle在Python对象和JSON / Javascript对象之间进行序列化。它包装simplejson并处理simplejson通常不接受的事情。

答案 5 :(得分:1)

将Java Script嵌入到Django模板中相当总是坏主意。

相反,因为此规则有一些例外情况。

一切都取决于您的Java Script代码站点和功能。

最好有单独的静态文件,比如JS,但问题是每个单独的文件都需要另一个连接/ GET /请求/响应机制。有时对于小的一个,两个衬垫代码os JS将其放入模板,然后使用django templatetags机制 - 你可以在其他模板中使用;)

关于对象 - 相同。如果你的网站有AJAX构造/ web2.0喜欢 - 你可以取得很好的效果,将一些计数/数学运算放到客户端。如果对象很小 - 嵌入到模板中,如果很大 - 在另一个连接中响应它们以避免用户的hangind页面。

答案 6 :(得分:1)

从2018年中期开始,最简单的方法是使用python的json模块,现在不建议使用simplejson。注意,正如@wilblack所提到的,您需要使用safe过滤器或带有autoescape选项的off标签来防止Django自动转义。在这两种情况下,您都将字典的内容添加到上下文中

viewset.py

import json def get_context_data(self, **kwargs): context['my_dictionary'] = json.dumps(self.object.mydict)

,然后在模板中添加为@wilblack建议:

template.html

<script> my_data = {{ my_dictionary|safe }}; </script>