将对象从Django传递到Javascript DOM

时间:2011-08-23 18:16:46

标签: javascript python django json dom

我正在尝试将来自Django的查询集传递给带有javascript的模板。

我尝试过不同的方法来解决这个问题:

1。正常方法 - 由于命名法[& gt Object:ID& lt,& gt Object:ID& lt,...]

Django View

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 View

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>

所以,我需要一些帮助:)

任何人都有任何建议/解决方案吗?

谢谢!

14 个答案:

答案 0 :(得分:29)

同样的问题,“更好”(更近期)回答:Django Queryset to dict for use in json

通过vashishtha-jogi回答:

  

更好的方法是使用DjangoJSONEncoder。它支持Decimal。

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

答案 1 :(得分:24)

好的,我找到了解决方案!

主要是因为没有引用结果。当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 );

我确信这可以改进,我告诉你;)

感谢您的回答

希望对别人有帮助!

答案 2 :(得分:7)

Django querysets are serializable by JSON。某些字段类型(例如日期,显然),无法序列化。日期对象的变通方法发布在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,我只是在视图中做一个循环并创建一个dict的列表,JSON没有序列化的问题,而且JavaScript没有理解的问题。

答案 3 :(得分:7)

编辑:请不要使用此方法,请参阅@ agconti的回答。

使用escapejs过滤器:https://docs.djangoproject.com/en/1.4/ref/templates/builtins/#escapejs

转储列表的示例:

var foo = [{% for x in y %}'{{ x|escapejs }}',{% endfor %}]

答案 4 :(得分:6)

您可以在Django中使用safeescapejs内置过滤器的组合。

var json_string = unescape({{json_list | safe | escapejs}});
var json_data = JSON.parse(json_string);

答案 5 :(得分:4)

您的问题是,通常情况下,您的要求不明确。你想要JSON看起来到底是什么样的?你说你想“序列化查询集”,但格式是什么?您想要每个模型实例,选择中的所有字段,还是只需要unicode表示?当你回答这个问题时,你就会知道如何解决问题。

例如,一种方法可能是使用values queryset方法为每个实例输出字段字典,并将其序列化(您需要先将其转换为列表):

data = SomeObject.objects.values('field1', 'field2', 'field3')
serialized_data = simplejson.dumps(list(data))

答案 6 :(得分: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或use | safe以避免所有&gt;内容

如果问题是处理复杂的python对象,你可能需要这样处理你的处理程序:JSON datetime between Python and JavaScript

答案 7 :(得分:2)

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过滤器将已经jsonized的对象从python导入javascript,就像这样......

data = {{ js_object|safe }}

这应该可以解决你的问题。

答案 8 :(得分:1)

自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> 
     

这是兼容的   具有严格的内容安全策略,该策略禁止页内脚本   执行。它还保持了被动数据之间的清晰隔离   和可执行代码。

答案 9 :(得分:0)

综合答案(我的环境: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 :(得分:0)

对我来说,发送整个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>

答案 11 :(得分:0)

注意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);

答案 12 :(得分:0)

要么;

使用{{ django_list }}读取对象,然后删除不需要的字符

或做;

{{ django_list | safe}}

答案 13 :(得分:0)

还要注意确保从Django正确输出JSON数据,否则前端的所有试验都将浪费时间。在我的情况下,我不能将JsonResponse用作render函数的一部分,所以我做了以下事情:

    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 %}