将对象从 Django 传递到 Javascript DOM
Posted
技术标签:
【中文标题】将对象从 Django 传递到 Javascript DOM【英文标题】:Passing objects from Django to Javascript DOM 【发布时间】:2011-11-02 04:47:33 【问题描述】:我正在尝试将一个查询集从 Django 传递到一个带有 javascript 的模板。
我尝试了不同的方法来解决这个问题:
1.正常方法 - 由于命名法 [ > Object:ID <, > Object:ID <,... ]
,Javascript 在尝试解析对象时变得一团糟Django 视图
django_list = list(Some_Object.objects.all())
模板 html + JS
<script type="text/javascript" >
var js_list = django_list;
</script>
2。 JSON 方法 - Django 无法将对象列表转换为 json 字符串 不是 JSON 可序列化的
Django 视图
django_list = list(Some_Object.objects.all())
json_list = simplejson.dumps(django_list)
模板 HTML + JS
<script type="text/javascript" >
var js_list = json_list;
</script>
所以,我需要一些帮助:)
任何人有任何建议/解决方案?
谢谢!
【问题讨论】:
【参考方案1】:Django 查询集are serializable by JSON。某些字段类型(例如日期,显然)不能在 is 序列化。日期对象的解决方法发布在another question on JSON and Python。
我建议直接在 JavaScript 本身中创建字典。给定这样的模型:
class Article(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField()
content = models.TextField()
class Author(models.Model):
article = models.ForeignKey("Article", related_name="authors")
first_name=models.CharField(max_length=100)
last_name=models.CharField(max_length=100)
我会在模板中做这样的事情:
<script type="text/javascript">
var articles = [
% for article in article_list %
% if not forloop.first %,% endif %
title: " article.title ",
slug: " article.slug ",
content: " article.content ",
authors: [
% for author in article.authors.all %
% if not forloop.first %,% endif %
first_name: " author.first_name ",
last_name: " author.last_name ",
% endfor %
]
% endfor %
]
</script>
如果您可能对这个问题的措辞有点糟糕,并且 不 计划在 <script>
标记中插入代码并且实际上出于某种原因需要 JSON,我' d 简单的在视图中做一个循环,创建一个dict
s 的列表,JSON 序列化没有问题,JavaScript 理解也没有问题。
【讨论】:
【参考方案2】:您的问题是,通常情况下,您的要求没有明确说明。您究竟希望 JSON 是什么样子?你说你想“序列化查询集”,但是用什么格式?你想要来自每个模型实例的所有字段、一个选择,还是只是 unicode 表示?当您回答了这个问题后,您就会知道如何解决您的问题。
例如,一种方法可能是使用values
queryset 方法为每个实例输出一个字段字典,并将其序列化(您需要先将其转换为列表):
data = SomeObject.objects.values('field1', 'field2', 'field3')
serialized_data = simplejson.dumps(list(data))
【讨论】:
嗨@Daniel,我想要一个对象列表,就像查询集一样。从 Javascript 的角度来看,这可能是一个对象数组。 叹息。您希望对象包含什么?【参考方案3】:您必须将字符串标记为安全,以确保它不会被转义。
在我的一个项目中,我这样使用它:
# app/templatetag/jsonify.py
from django import template
from django.utils.safestring import mark_safe
import json
register = template.Library()
@register.filter
def jsonify(list):
return mark_safe(json.dumps(list))
在模板中
% load jsonify %
<script type="text/javascript" >
var js_list = python_list|jsonify|escapejs ;
</script>
但您可能更喜欢只添加 mark_safe 或在模板中使用 |safe 以避免所有 &gt;
内容
如果问题在于处理复杂的 python 对象,您可能必须像这样执行处理程序:JSON datetime between Python and JavaScript
【讨论】:
这很容易受到 XSS 攻击。例如,尝试以下 Python 列表:['</script><script>alert("hello")//']
.
你是对的,在这种情况下,除非模板呈现 .js 文件,否则我们应该添加我忘记的“|escapejs”,我编辑了,谢谢 Blender【参考方案4】:
好的,我找到了解决方案!
主要是因为没有引用结果。当 Javascript 试图解析对象时,这未被识别为字符串。
所以,第一步是:
var js_list = django_list;
改为:
var js_list = "django_list";
在这之后我意识到 Django 正在转义字符,所以我不得不像这样替换它们:
var myJSONList = (("json_list").replace(/&(l|g|quo)t;/g, function(a,b)
return
l : '<',
g : '>',
quo : '"'
[b];
));
myData = JSON.parse( myJSONList );
注意:我试图避免使用 Django 转义字符:
var js_list = "json_list|safe";
但这不起作用,因为它与引号混淆。
最后我找到了一种方法来避免在将其发送到 Javascript 之前将其转换为 JSON 的后端逻辑:
var myDjangoList = (("django_list |safe").replace(/&(l|g|quo)t;/g, function(a,b)
return
l : '<',
g : '>',
quo : '"'
[b];
));
myDjangoList = myDjangoList.replace(/u'/g, '\'')
myDjangoList = myDjangoList.replace(/'/g, '\"')
myData = JSON.parse( myDjangoList );
我确信这可以改进,我把这个告诉你;)
感谢您的回答
希望对其他人有所帮助!
【讨论】:
这个答案不是一个优雅的方法。试试***.com/questions/10502135/… 事实证明,该链接问题的答案也不是很好。 Json.dumps 不再起作用,需要使用序列化程序。现在,这是一个很好的方法,但是对于传递给模板的模型的简单 values_list 函数,此答案中的方法有效。【参考方案5】:Django 为您在此处尝试执行的场景提供内置帮助。它是这样的:
您的视图中有一个 python 序列、列表、字典等,我们称之为py_object
。一种方法是在将其传递给渲染引擎之前对其进行 jsonify。
from django.shortcuts import render_to_response
import json
以后就这样用了……
render_to_response('mypage.html','js_object':json.dumps(py_object))
在您的模板中,然后使用 safe
过滤器将已经 json 化的对象从 python 导入到 javascript 中,像这样...
data = js_object|safe
我希望这应该能解决你的问题。
【讨论】:
【参考方案6】:编辑:请不要使用此方法,请参阅@agconti 的回答。
使用 escapejs 过滤器:https://docs.djangoproject.com/en/1.4/ref/templates/builtins/#escapejs
转储列表示例:
var foo = [% for x in y %' x|escapejs ',% endfor %]
【讨论】:
如果我有一个嵌套列表怎么办?那我该如何转储呢?使用上面的代码,我只得到第一级的项目。任何帮助将不胜感激。 @HarshMehta 看到下面我的答案:使用 DjangoJSONEncoder。【参考方案7】:同样的问题,“更好”(最近)答案:Django Queryset to dict for use in json
vashishtha-jogi回复:
更好的方法是使用 DjangoJSONEncoder。它支持小数。
import json from django.core.serializers.json import DjangoJSONEncoder prices = Price.objects.filter(product=product).values_list('price','valid_from') prices_json = json.dumps(list(prices), cls=DjangoJSONEncoder)
非常易于使用。无需为转换个人而跳槽 字段浮动。
更新:将答案更改为使用内置 json 而不是 simplejson。
这个答案在我的谷歌搜索中经常出现,并且有很多观点,更新它似乎是个好主意,让其他人免于挖掘 SO。假设Django 1.5
。
【讨论】:
除了.values_list()
,也可以使用.values()
来获取所有内容
prices_json被创建并传递给DOM后,你也可以通过var prices_data= prices_json|safe ;
将其内容赋给一个Javascript变量【参考方案8】:
您可以在 Django 中使用safe 和escapejs 内置过滤器的组合。
var json_string = unescape(json_list | safe | escapejs);
var json_data = JSON.parse(json_string);
【讨论】:
安全 |逃跑是另一种在其他时间起作用的可能性【参考方案9】:综合答案(我的环境:Django 2.0)
在views.py中
import json
data= []
// fil the list
context['mydata'] = json.dumps('data':data)
在模板中
<script type="text/javascript">
var mydataString = "mydata|escapejs";
console.log(JSON.parse(mydataString));
</script>
【讨论】:
【参考方案10】:从 Django 2.1 开始,就有了json-script template tag。来自文档:
json_script
将 Python 对象安全地输出为 JSON,包装在标签中, 准备好与 JavaScript 一起使用。
参数:标签的 HTML “id”。
例如:
value|json_script:"hello-data"
如果 value 是字典
'hello': 'world'
,输出将是:<script id="hello-data" type="application/json"> "hello": "world" </script>
可以在 JavaScript 中访问结果数据 像这样:
var value = JSON.parse(document.getElementById('hello-data').textContent);
通过转义字符“”和“&”可以缓解 XSS 攻击。为了 例如,如果值为
'hello': 'world</script>&amp;'
,则输出为:<script id="hello-data" type="application/json"> "hello": "world\\u003C/script\\u003E\\u0026amp;" </script>
这是兼容的 具有禁止页内脚本的严格内容安全策略 执行。它还保持被动数据之间的清晰分离 和可执行代码。
【讨论】:
【参考方案11】:让我发送整个 QuerySet(同时保留字段名称;发送 object
而不是 list
)。我用了以下
# views.py
units = Unit.objects.all()
units_serialized = serializers.serialize('json', units)
context['units'] = units_serialized
只需在模板中使用safe
标记
# template.html
<script>
console.log(units|safe);
</script>
【讨论】:
【参考方案12】:django 2.1 的注意事项
我在 django 文档中发现这有点令人困惑,所以简单地解释一下简单的方法。
我们通常会像这样使用它
my_info
或根据我们的需要循环它。但是如果我们使用下面的过滤器,
json_script
我们可以安全地将这个值输出为 JSON
my_info|json_script:"my-info"
我们的数据以 JSON 格式添加,包装在脚本标签中,我们可以看到数据。我们现在可以通过在 JavaScript 中查找来使用这个值,如下所示:
info = JSON.parse(document.getElementById('my-info').textContent);
【讨论】:
【参考方案13】:要么;
使用 django_list
读取对象,然后删除不需要的字符
或者做;
django_list | safe
【讨论】:
【参考方案14】:还要注意确保从 Django 正确输出 JSON 数据,否则前端的所有试验都将浪费时间。在我的情况下,我不能使用 JsonResponse 作为渲染函数的一部分,所以我做了以下事情:
def view(self, request):
data = []
machine_data = list(Machine.objects.filter(location__isnull=False).values_list('serial', 'location', 'customer__name'))
data.append(
"locations": machine_data,
)
return render(request, 'admin/company/device/map.html',
"machines": data
)
在前端:
% block content %
machines_with_location|json_script:"machineLocationData"
<div id="content-main">
<h1>Title</h1>
<script type="text/javascript">
const locationDataFromJson = JSON.parse(document.getElementById('machineLocationData').textContent);
</script>
</div>
% endblock %
【讨论】:
以上是关于将对象从 Django 传递到 Javascript DOM的主要内容,如果未能解决你的问题,请参考以下文章