Шаблонные переменные Django и Javascript

155

Когда я создаю страницу с помощью средства визуализации Django, я могу передать переменную словаря, содержащую различные значения, чтобы манипулировать ими на странице с помощью {{ myVar }}.

Есть ли способ получить доступ к одной и той же переменной в Javascript (возможно, используя DOM, я не знаю, как Django делает переменные доступными)? Я хочу иметь возможность искать информацию, используя поиск AJAX, основанный на значениях, содержащихся в переданных переменных.

Теги:
django-templates
google-app-engine

11 ответов

246
Лучший ответ

{{variable}} подставляется непосредственно в HTML. Использовать источник просмотра; это не "переменная" или что-то в этом роде. Он просто визуализировал текст.

Сказав это, вы можете поместить такую ​​замену в свой JavaScript.

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}";
</script>

Это дает вам "динамический" javascript.

  • 22
    Обратите внимание, что в соответствии с этим решением это уязвимо для инъекционных атак
  • 13
    @Casebash: для таких случаев существует фильтр escapejs : escapejs('<>') -> u'\\u003C\\u003E'
Показать ещё 9 комментариев
45

ПРЕДОСТЕРЕЖЕНИЕ Проверить флажок # 17419 для обсуждения добавления подобного тега в ядро ​​Django и возможных уязвимостей XSS, введенных с помощью этот тег шаблона с пользовательскими данными. Comment от amacneil обсуждает большую часть проблем, поднятых в билете.


Я думаю, что самый гибкий и удобный способ сделать это - определить фильтр шаблонов для переменных, которые вы хотите использовать в JS-коде. Это позволяет гарантировать, что ваши данные будут правильно экранированы, и вы можете использовать его со сложными структурами данных, такими как dict и list. Вот почему я пишу этот ответ, несмотря на то, что есть принятый ответ с большим количеством проблем.

Вот пример фильтра шаблонов:

// myapp/templatetags/js.py

from django.utils.safestring import mark_safe
from django.template import Library

import json


register = Library()


@register.filter(is_safe=True)
def js(obj):
    return mark_safe(json.dumps(obj))

Этот шаблон фильтрует преобразование переменной в строку JSON. Вы можете использовать его так:

// myapp/templates/example.html

{% load js %}

<script type="text/javascript">
    var someVar = {{ some_var | js }};
</script>
  • 3
    Это хорошо, потому что он позволяет копировать только некоторые входные переменные шаблона Django в Javascript, и серверный код не должен знать, какие структуры данных должны использоваться Javascript и, следовательно, преобразовываться в JSON перед рендерингом шаблона Django. Либо используйте это, либо всегда копируйте все переменные Django в Javascript.
  • 0
    Но обратите внимание: stackoverflow.com/questions/23752156/…
Показать ещё 6 комментариев
38

Решение, которое сработало для меня, использует скрытое поле ввода в шаблоне

<input type="hidden" id="myVar" name="variable" value="{{ variable }}">

Затем, получив значение в javascript таким образом,

var myVar = document.getElementById("myVar").value;
  • 3
    будь осторожен, хотя. в зависимости от того, как вы используете переменную / форму, пользователь может добавить что угодно.
  • 1
    Вы также можете установить поле ввода только для чтения (см. эту ссылку w3schools.com/tags/att_input_readonly.asp ).
Показать ещё 4 комментария
8

Для словаря, вы лучше всего кодируете JSON. Вы можете использовать simplejson.dumps() или если вы хотите преобразовать из модели данных в App Engine, вы можете использовать encode() из библиотеки GQLEncoder.

  • 2
    Этот подход сработал после того, как я выключил django autoescape.
  • 0
    Обратите внимание, что, начиная с django 1.7, «simplejson» стал «json».
7

Когда переменная возвращается Django, она превращает все кавычки в &quot;. Использование {{someDjangoVariable|safe}} вызывает ошибку Javascript.

Чтобы исправить это, используйте Javascript .replace:

<script type="text/javascript"> 
    var json = "{{someDjangoVariable}}".replace(/&quot;/g,"\"")
</script>
  • 0
    Я никогда не думал об этом ... отличная идея!
  • 2
    Используйте escapejs шаблон escapejs вместо .replace(..)
6

Вот что я делаю очень легко: Я изменил файл base.html для своего шаблона и поместил его внизу:

{% if DJdata %}
    <script type="text/javascript">
        (function () {window.DJdata = {{DJdata|safe}};})();
    </script>
{% endif %}

то когда я хочу использовать переменную в файлах javascript, я создаю словарь DJdata и добавляю его в контекст json: context['DJdata'] = json.dumps(DJdata)

Надеюсь, что это поможет!

  • 2
    Это потрясающе, спасибо!
3

Я столкнулся с проблемой simillar, и ответ, предложенный S.Lott, работал на меня.

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}"
</script>

Однако я хотел бы указать здесь значительное ограничение реализации. Если вы планируете разместить свой javascript-код в другом файле и включить этот файл в свой шаблон. Это не сработает.

Это работает только тогда, когда основной шаблон и код javascript находятся в одном файле. Возможно, команда django может решить эту проблему.

  • 1
    Как мы можем преодолеть это?
  • 1
    Чтобы преодолеть это, вы можете разместить глобальные переменные Javascript, как показано в примере, перед тем как включить статический файл Javascript. Таким образом, ваш статический файл Javascript будет иметь доступ ко всем глобальным переменным.
1

Я тоже боролся с этим. На первый взгляд кажется, что вышеуказанные решения должны работать. Однако архитектура django требует, чтобы у каждого html файла были свои отображаемые переменные (то есть {{contact}} отображается в contact.html, а {{posts}} - например, index.html и т.д.). С другой стороны, теги <script> появляются после {%endblock%} в base.html от которого наследуются contact.html и index.html. Это в основном означает, что любое решение, включая

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>

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

Простое решение, которое я в конечном итоге придумал и сработало для меня, заключалось в том, чтобы просто обернуть переменную тегом с id и затем обратиться к нему в файле js, например, так:

// index.html
<div id="myvar">{{ myVar }}</div>

а потом:

// somecode.js
var someVar = document.getElementById("myvar").innerHTML;

и просто <script src="/somecode.js"></script> в base.html как обычно. Конечно, это только получение контента. Что касается безопасности, просто следуйте другим ответам.

0

Начиная с Django 2.1, новый встроенный тег шаблона был введен специально для этого json_script использования: json_script.

https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#json-script.

Новый тег безопасно сериализует значения шаблона и защищает от XSS.

0

Обратите внимание, что если вы хотите передать переменную во внешний скрипт .js, то вам нужно предшествовать вашему тегу скрипта с другим тегом скрипта, который объявляет глобальную переменную.

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>

<script type="text/javascript" src="{% static "scripts/my_script.js" %}"></script>

data определяются в представлении как обычно в get_context_data

def get_context_data(self, *args, **kwargs):
    context['myVar'] = True
    return context
0

Для объекта JavaScript, хранящегося в поле Django в качестве текста, который должен снова стать объектом JavaScript, динамически вставленным на страницу script, вам необходимо использовать как escapejs, так и JSON.parse():

var CropOpts = JSON.parse("{{ profile.last_crop_coords|escapejs }}");

Django escapejs корректно обрабатывает цитирование, а JSON.parse() преобразует строку обратно в объект JS.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню