Передача объектов из Django в Javascript DOM - PullRequest
30 голосов
/ 23 августа 2011

Я пытаюсь передать Query Set из Django в шаблон с javascript.

Я пробовал разные подходы для решения этой проблемы:

1.Нормальный подход - Javascript запутывается при попытке разобрать объект из-за номенклатуры [> Object: ID <,> Object: ID <, ...] </strong>

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

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>

Итак, мне нужна помощь здесь:)

У кого-нибудь есть предложения / решения?

Спасибо!

Ответы [ 10 ]

29 голосов
/ 14 августа 2013

Тот же вопрос, «Лучше» ( более поздний ) ответ: Django Queryset для использования в 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.

Этот ответ возникал так часто в моих поисках в Google и имеет так много просмотров, что кажется хорошей идеей обновить его и спасти кого-нибудь еще от копания в SO. Принимает Django 1.5.

25 голосов
/ 24 августа 2011

Хорошо, я нашел решение!

В основном это было из-за того, что не цитировал результаты.Когда 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}}"; 

Но это не работает, потому что его путают с кавычками.

Наконец, я нашел способ избежать логики в бэкэнде преобразования в JSON перед отправкой его в Javascript:

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

Я уверен, что это можно улучшить, я позволю вам это;)

Спасибо за ваши ответы

Надеюсь, это поможет кому-то еще!

8 голосов
/ 23 августа 2011

Наборы запросов Django , сериализуемые JSON .Некоторые типы полей (например, дата, по-видимому) не могут быть сериализованы в is.Обходной путь для объектов даты опубликован в , еще один вопрос по JSON и 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 s, который имеет JSONнет проблем с сериализацией, а в JavaScript нет проблем с пониманием.

7 голосов
/ 29 декабря 2012

РЕДАКТИРОВАТЬ: пожалуйста, не используйте этот метод, см. Ответ @ agconti.

Используйте фильтр escapejs: https://docs.djangoproject.com/en/1.4/ref/templates/builtins/#escapejs

Пример вывода списка:

var foo = [{% for x in y %}'{{ x|escapejs }}',{% endfor %}]
6 голосов
/ 14 июля 2014

Вы можете использовать комбинацию safe и escapejs встроенный фильтр в Django.

var json_string = unescape({{json_list | safe | escapejs}});
var json_data = JSON.parse(json_string);
4 голосов
/ 23 августа 2011

Ваша проблема в том, что, как это часто бывает, ваши требования недооценены. Как именно вы хотите, чтобы JSON выглядел? Вы говорите, что хотите «сериализовать набор запросов», но в каком формате? Вам нужны все поля из каждого экземпляра модели, выбора или просто представления в юникоде? Когда вы ответите на этот вопрос, вы узнаете, как решить вашу проблему.

Один из подходов, например, может заключаться в использовании метода набора запросов values для вывода словаря полей для каждого экземпляра и его сериализации (сначала необходимо преобразовать его в список):

data = SomeObject.objects.values('field1', 'field2', 'field3')
serialized_data = simplejson.dumps(list(data))
3 голосов
/ 19 сентября 2018

Начиная с Django 2.1, есть шаблонный тег json . Из документов:

json_script

Безопасно выводит объект Python в виде JSON, обернутый в тег, готов к использованию с JavaScript.

Аргумент: HTML-идентификатор тега.

Например:

{{ value|json_script:"hello-data" }} 

Если значением является словарь {'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> 

Это совместимо со строгой политикой безопасности контента, которая запрещает скрипты на странице выполнение. Он также поддерживает четкое разделение между пассивными данными. и исполняемый код.

3 голосов
/ 23 августа 2011

Вы должны пометить строку как безопасную, чтобы быть уверенным, что она не экранирована.

в одном из моих проектов я использую ее так:

# 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; stuff

Если проблема в обработке сложного объекта python, возможно, вам придетсятакой обработчик: JSON datetime между Python и JavaScript

2 голосов
/ 04 февраля 2012

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

Это должно решить вашу проблему, я надеюсь.

0 голосов
/ 25 апреля 2018

Сводный ответ (мой env: 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...