Подтвердить что ты не робот

Возвращение массива JSON из представления Django в шаблон

Я использую Django для создания веб-приложения для проекта, и у меня возникают проблемы с возвратом массива из представления Django в шаблон.

Массив будет использоваться JavaScript (JQuery) script для рисования на изображении, показанном на странице. Следовательно, этот массив будет иметь, среди прочего, координаты для рисования полей.

Это код в представлении 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, ...})

Как способ отладки, использование {{ tags }} в HTML-части шаблона дает это как результат (извините за длинную строку):

[{"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.

Позже в шаблоне я пытаюсь использовать переменную tags в части JavaScript шаблона следующим образом:

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

Если я удалю строку var tgs = JSON.parse(tagbs);, тогда появится окно предупреждения, а остальная часть JavaScript работает так, как ожидалось. Однако оставить эту строку при разрыве script.

Я хочу, чтобы иметь возможность перебирать все объекты в модели Django и получать значения полей в JavaScript.

Я не уверен, что я здесь делаю неправильно, мог ли кто-нибудь указать правильный способ сделать это?

4b9b3361

Ответ 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>

Этот тег имеет специальную обработку строк, содержащих "& lt;/script & gt;" чтобы убедиться, что они работают.

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. То есть JSON-представление массива - это исходный код Javascript, необходимый для определения массива.

Итак, после:

var tagbs = {{ tags|safe }};

tagbs - это массив JavaScript, содержащий нужные данные. Нет необходимости вызывать JSON.parse(), потому что веб-браузер уже проанализировал его как исходный код JavaScript.

Так что вы должны быть в состоянии сделать

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

и это должно показать "4".

ПРЕДУПРЕЖДЕНИЕ. С этим старым методом строки, содержащие "& lt;/script & gt;" не будет работать, они пойдут ужасно неправильно. Это связано с тем, что браузер будет обрабатывать & lt;/script & gt; как конец сценария. Если какая-либо из строк представляет собой введенные пользователем данные, это уязвимость в уязвимости - см. Комментарий 14 здесь для получения дополнительной информации. Вместо этого используйте более современный метод выше.

Ответ 2

Вы хотите использовать JSON-ify данные в шаблоне; JSON уже Javascript действительно (это подмножество:

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

Обратите внимание, что tags уже является данными JSON (таким образом, JavaScript) и может быть вставлен напрямую; нет необходимости бежать (здесь нет HTML-кода, вместо него используется JavaScript).

Или вы можете использовать этот фрагмент Django и сделать это прямо в шаблоне (нет необходимости вызывать serializers.serialize в методе annotate):

var tgs = {{ tags|jsonify }};

Ответ 3

Вы также можете использовать simplejson от django.utils. Как:

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

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

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