Передача данных Python в JavaScript через Django - PullRequest
52 голосов
/ 18 сентября 2009

Я использую Django и Apache для обслуживания веб-страниц. Мой код JavaScript в настоящее время включает в себя объект данных со значениями, которые будут отображаться в различных HTML-виджетах на основе выбора пользователя из меню выбора. Я хочу получить эти данные из словаря Python. Я думаю, что знаю, как встроить код JavaScript в HTML, но как мне вставить объект данных в этот скрипт (на лету), чтобы функции скрипта могли его использовать?

Другими словами, я хочу создать объект или массив JavaScript из словаря Python, затем вставить этот объект в код JavaScript, а затем вставить этот код JavaScript в HTML.

Я полагаю, что эта структура (например, данные, встроенные в переменные в коде JavaScript) является неоптимальной, но как новичок я не знаю альтернатив. Я видел рецензии на функции сериализации Django, но они не помогают мне, пока я не получу данные в свой код JavaScript.

Я (пока) не использую библиотеку JavaScript, такую ​​как jQuery.

Ответы [ 7 ]

78 голосов
/ 18 сентября 2009

n.b. см. обновление 2018 внизу

Я рекомендую не добавлять много JavaScript в ваши шаблоны Django - его сложно писать и отлаживать, особенно по мере расширения вашего проекта. Вместо этого попробуйте написать весь свой JavaScript в отдельном файле сценария, который загружает ваш шаблон, и просто включить в шаблон только объект данных JSON. Это позволяет вам выполнять такие вещи, как запуск всего приложения JavaScript через что-то вроде JSLint , минимизацию его и т. Д., И вы можете протестировать его в статическом HTML-файле без каких-либо зависимостей в приложении Django. Использование такой библиотеки, как simplejson, также экономит время, затрачиваемое на написание утомительного кода сериализации.

Если вы не предполагаете, что создаете приложение AJAX, это может быть сделано просто так:

По виду:

from django.utils import simplejson


def view(request, …):
    js_data = simplejson.dumps(my_dict)
    …
    render_template_to_response("my_template.html", {"my_data": js_data, …})

В шаблоне:

<script type="text/javascript">
    data_from_django = {{ my_data }};
    widget.init(data_from_django);
</script>

Обратите внимание, что тип данных имеет значение: если my_data - это простое число или строка из контролируемого источника, который не содержит HTML, такого как отформатированная дата, никакой специальной обработки не требуется. Если есть возможность получить ненадежные данные, предоставленные пользователем, вам необходимо очистить их, используя что-то вроде escape или escapejs , и убедитесь, что ваш JavaScript безопасно обрабатывает данные, чтобы избежать межсайтовый скриптинг атак.

Что касается дат, вы также можете подумать о том, как вы проводите даты. Я почти всегда считал, что проще всего передавать их как метки времени Unix:

В Джанго:

time_t = time.mktime(my_date.timetuple())

В JavaScript, если вы сделали что-то вроде time_t = {{ time_t }} с результатами приведенного выше фрагмента:

my_date = new Date();
my_date.setTime(time_t*1000);

Наконец, обратите внимание на UTC - вам нужно, чтобы функции даты Python и Django обменивались данными в UTC, чтобы избежать смущающих сдвигов от местного времени пользователя.

РЕДАКТИРОВАТЬ: Обратите внимание, что setTime в javascript находится в миллисекундах, тогда как вывод time.mktime составляет секунды. Вот почему нам нужно умножить на 1000

2018 Обновление: мне все еще нравится JSON для сложных значений, но за прошедшее десятилетие API данных HTML5 достиг почти универсальной поддержки браузера , и это очень удобно для передачи простых (не список / dict) значений, особенно если вы хотите, чтобы правила CSS применялись на основе этих значений, и вам не нужны неподдерживаемые версии Internet Explorer.

<div id="my-widget" data-view-mode="tabular">…</div>

let myWidget = document.getElementById("my-widget");
console.log(myWidget.dataset.viewMode); // Prints tabular
somethingElse.addEventListener('click', evt => {
    myWidget.dataset.viewMode = "list";
});

Это отличный способ представить данные в CSS, если вы хотите установить начальное состояние просмотра в шаблоне Django и автоматически обновлять его, когда JavaScript обновляет атрибут data-. Я использую это для таких вещей, как скрытие виджета прогресса до тех пор, пока пользователь не выберет что-то для обработки или для условного отображения / скрытия ошибок на основе результатов выборки, или даже для отображения количества активных записей с использованием CSS, например #some-element::after { content: attr(data-active-transfers); }.

38 голосов
/ 09 ноября 2012

Для тех, у кого могут быть проблемы с этим, убедитесь, что вы отображаете свой объект json в безопасном режиме в шаблоне. Вы можете вручную установить это так:

<script type="text/javascript">
    data_from_django = {{ my_data|safe }};
    widget.init(data_from_django);
</script>
3 голосов
/ 18 сентября 2009

Вы можете включить теги <script> в свои шаблоны .html, а затем создавать структуры данных, как вам удобно. Язык шаблонов предназначен не только для HTML, но и для литералов объектов Javascript.

И Пол прав: возможно, лучше всего использовать модуль json для создания строки JSON, а затем вставить эту строку в шаблон. Это лучше всего решит проблемы с цитированием и с легкостью справится с глубокими структурами.

2 голосов
/ 18 сентября 2009

Это неоптимально. Рассматривали ли вы передачу своих данных в формате JSON, используя для этого встроенный сериализатор django?

1 голос
/ 28 августа 2018

по состоянию на середину 2018 года самый простой подход заключается в использовании json-модуля Python, simplejson теперь не рекомендуется. Помните, что, как упоминает @wilblack, вам нужно предотвратить автоэкранирование Django, используя фильтр safe или тег autoescape с параметром off. В обоих случаях в представлении вы добавляете содержимое словаря в контекст

viewset.py

import json def get_context_data(self, **kwargs): context['my_dictionary'] = json.dumps(self.object.mydict)

и затем в шаблоне, который вы добавляете, как предложил @wilblack:

template.html

<script> my_data = {{ my_dictionary|safe }}; </script>

1 голос
/ 19 сентября 2009

Помещение Java Script в шаблон Django - это , а точнее - всегда плохая идея.

Скорее , потому что есть некоторые исключения из этого правила.

Все зависит от вашего сайта и функциональности кода Java Script.

Лучше иметь отдельные статические файлы, такие как JS, но проблема в том, что для каждого отдельного файла нужен другой механизм connect / GET / request / response. Иногда для небольшого кода два кода для JS, чтобы поместить это в шаблон, затем использовать механизм шаблонных тегов django - вы можете использовать его в других шаблонах;)

Об объектах - то же самое. Если у вашего сайта есть AJAX construction / web2.0, как одолжение - вы можете добиться очень хорошего эффекта, применяя некоторые операции подсчета / математики на стороне клиента. Если объекты маленькие - встроены в шаблон, если большие - ответьте на них в другом соединении, чтобы избежать зависания страницы для пользователя.

1 голос
/ 19 сентября 2009

См. Соответствующий ответ на этот вопрос . Один из вариантов - использовать jsonpickle для сериализации между объектами Python и объектами JSON / Javascript. Он упаковывает simplejson и обрабатывает вещи, которые обычно не принимаются simplejson.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...