Змінні шаблону Django та Javascript


219

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

Чи є спосіб отримати доступ до тієї ж змінної у Javascript (можливо, використовуючи DOM, я не знаю, як Django робить доступними змінні)? Я хочу мати змогу шукати деталі за допомогою пошуку AJAX на основі значень, що містяться у переданих змінних.

Відповіді:


291

{{variable}}Замінюється безпосередньо в HTML. У джерела перегляду; це не "змінна" чи щось подібне. Це просто виведений текст.

Сказавши це, ви можете помістити таку заміну у свій JavaScript.

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

Це дає вам "динамічний" javascript.


29
Зауважте, що згідно з цим рішенням , це є вразливим до атак ін'єкцій
Casebash

13
@Casebash: Для таких випадків escapejsіснує фільтр:escapejs('<>') -> u'\\u003C\\u003E'
Tomasz Zieliński

24
Просто для доповнення до цього: якщо "someDjangoVariable" трапляється як JSON, обов'язково використовуйте {{someDjangoVariable | safe}} для видалення & quot;
Марк

4
Ця відповідь працює лише для простої змінної, вона не працює для складної структури даних. У цьому випадку найпростішим рішенням є додати код на стороні клієнта для переходу структури даних та побудови подібного в Javascript. Якщо складна структура даних знаходиться у форматі JSON, іншим рішенням є її серіалізація, передача серіалізованого JSON до шаблону Django у коді на стороні сервера та деріаріалізація JSON в об'єкті javascript у коді на стороні клієнта. Одна відповідь нижче згадує цю альтернативу.
Алан Євангеліста

14
що робити, якщо javascript записаний у іншому файлі?
the_unknown_spirit

64

ПОПЕРЕДЖЕННЯ Перевірте білет №17419 для обговорення щодо додавання подібного тегу до ядра Django та можливих уразливостей XSS, введених за допомогою цього тегу шаблону з даними, створеними користувачем. Коментар 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.
Алан Евангеліста


1
@JorgeOrpinel Ні, це не те саме. safeлише маркує значення як безпечне, без належної конверсії та уникнення.
Ярослав Адмін

2
Як ви відображаєте змінну в шаблоні django?
kbdev

1
@Sandi назад, коли я розмістив його, звичайно було мати віджет в окремому файлі JS та ініціалізувати його у вихідному коді сторінки. Тож скажімо, що ви заявляєте function myWidget(config) { /* implementation */ }у файлі JS, а потім використовуєте його на деяких сторінках myWidget({{ pythonConfig | js }}). Але ви не можете використовувати його у файлах JS (як ви помітили), тому у нього є свої обмеження.
Ярослав Адмін

51

Рішення, яке працювало для мене, - це використання прихованого поля введення в шаблоні

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

Потім отримуючи значення в JavaScript таким чином,

var myVar = document.getElementById("myVar").value;

3
будьте обережні, хоча. залежно від того, як ви використовуєте змінну / форму, користувач може розмістити все, що хоче.
AndyL

3
ви також можете встановити поле для введення лише для читання (див. це посилання w3schools.com/tags/att_input_readonly.asp )
nu everest

Якщо це щось, що не змінить базу даних або не буде відправлено на запит до бази даних, це буде добре. @AndyL
James111

3
Хлопці ... користувачі можуть робити все, що завгодно. Сьогодні браузери роблять це дуже просто за допомогою повнофункціонального інспектора DOM та інструментів налагодження. Мораль історії: зробіть ВСЕ вами перевірку даних на сервері .
користувач2867288

1
Будь ласка, будь-хто може сказати мені, як би ви отримали доступ до цієї змінної у зовнішньому файлі JavaScript?
Ахтішам

27

Станом на Django 2.1, новий вбудований тег шаблону був введений спеціально для цього випадку використання: json_script .

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

Новий тег надійно серіалізує значення шаблону та захищає від XSS.

Уривок з документа Django:

Безпечно виводить об’єкт Python як JSON, загорнутий у тег, готовий до використання з JavaScript.


10

Ось що я роблю дуже легко: я змінив файл base.html для свого шаблону і поставив його внизу:

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

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

Сподіваюся, це допомагає!


Не використовуйте це, воно вразливе до введення сценарію (XSS).
pcworld

8

Щодо словника, то найкраще спочатку кодувати JSON. Ви можете використовувати simplejson.dumps () або якщо ви хочете конвертувати з моделі даних в App Engine, ви можете використовувати encode () з бібліотеки GQLEncoder.


1
Зауважте, що "simplejson" став "json" станом на django 1.7, я вважаю.
п'ять клубів

4

Я зіткнувся з подібним питанням і відповідь, запропонована С.Лоттом, працювала на мене.

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

Однак я хотів би зазначити тут головне обмеження щодо впровадження . Якщо ви плануєте помістити свій код JavaScript в інший файл і включити цей файл у свій шаблон. Це не спрацює.

Це працює лише тоді, коли ви основний шаблон і код JavaScript в одному файлі. Можливо, команда джанго може вирішити це обмеження.


1
Як ми можемо це подолати?
Csaba Toth

2
Щоб подолати це, ви можете розмістити глобальні змінні Javascript, як приклад, показаний перед тим, як включити статичний файл Javascript. Ваш статичний файл Javascript матиме доступ до всіх глобальних змінних таким чином.
Бобборт

Не використовуйте це, воно вразливе до введення сценарію (XSS).
pcworld

Вони можуть перевіряти дані на стороні сервера.
Мухаммед Файзан Фарід

4

Я теж боровся з цим. На поверхні здається, що вищезазначені рішення повинні працювати. Однак архітектура 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="static/js/somecode.js"></script>в , base.htmlяк зазвичай. Звичайно, мова йде лише про отримання вмісту. Щодо безпеки, просто дотримуйтесь інших відповідей.


Ви, мабуть, хочете використовувати .textContentзамість цього .innerHTML, тому що в іншому випадку об'єкти, які кодують HTML, також будуть частиною змінної JS. Але навіть тоді це не може бути відтворено 1: 1 (я не впевнений).
pcworld

Уточнення . Я використовую аналогічний спосіб збору значень поля у змінні (використовуючи динамічно створені у формі ідентифікатори), і він працює (але лише для одного ряду наборів форматів ). Те, що я не в змозі обійти, - це фіксувати значення з усіх рядків полів наборів , які заповнюються вручну (тобто в таблиці HTML, що використовується для циклу ). Як ви будете візуалізувати, змінні лише останнього рядка формату передаються змінним, а значення перед цим перезаписуються останніми значеннями, коли цикл for прогресує через рядки набору форматів. Чи є шлях до цього?
користувач12379095

3

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

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

Django escapejsобробляє цитування належним чином і JSON.parse()перетворює рядок назад в JS-об'єкт.


2

Зауважте, що якщо ви хочете передати змінну зовнішньому скрипту .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

Частина оголосити змінну в усьому світі була фактично корисною.
Рахуль

якщо ви візуалізуєте дані у js-змінні з таких шаблонів, як і раніше, вони повинні відображатись на одній сторінці (робити їх глобальною), а інший код переходить у окремий js-файл. На стороні сервера повинні бути дійсні дані, оскільки користувач може змінюватись від браузера.
Мухаммед Файзан Фарід

1

Я використовую цей спосіб у Django 2.1 і працюю для мене, і цей спосіб безпечний (довідковий) :

Сторона Джанго:

def age(request):
    mydata = {'age':12}
    return render(request, 'test.html', context={"mydata_json": json.dumps(mydata)})

Html сторона:

<script type='text/javascript'>
     const  mydata = {{ mydata_json|safe }};
console.log(mydata)
 </script>

0

ви можете зібрати весь сценарій, де ваша змінна масив оголошена в рядку,

views.py

    aaa = [41, 56, 25, 48, 72, 34, 12]
    prueba = "<script>var data2 =["
    for a in aaa:
        aa = str(a)
        prueba = prueba + "'" + aa + "',"
    prueba = prueba + "];</script>"

що створить рядок наступним чином

prueba = "<script>var data2 =['41','56','25','48','72','34','12'];</script>"

після цього рядка ви повинні надіслати його до шаблону

views.py

return render(request, 'example.html', {"prueba": prueba})

у шаблоні ви отримуєте його та інтерпретуєте його літературним чином як htm-код, безпосередньо перед кодом javascript, де вам це потрібно, наприклад

шаблон

{{ prueba|safe  }}

і нижче - решта вашого коду, майте на увазі, що змінна, яка використовується у прикладі, - це data2

<script>
 console.log(data2);
</script>

таким чином ви збережете тип даних, що в даному випадку є розташуванням


Використовуйте це лише в тому випадку, якщо ви впевнені, що вони aaaбудуть містити лише цифри, інакше можливий XSS (введення сценарію).
pcworld

0

Є дві речі, які працювали для мене всередині Javascript:

'{{context_variable|escapejs }}'

та інше: У views.py

from json import dumps as jdumps

def func(request):
    context={'message': jdumps('hello there')}
    return render(request,'index.html',context)

і в html:

{{ message|safe }}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.