AngularJS з Django - конфліктуючі теги шаблонів


302

Я хочу використовувати AngularJS з Django, однак вони обидва використовують {{ }}як свої теги шаблонів. Чи є простий спосіб змінити один з двох, щоб використовувати якийсь інший спеціальний тег шаблону?


1
Я виводжу лише один шаблон із templatesкаталогу django , решту я вкладаю static. Таким чином, у вас немає втручання. Тут я написав підручник: coderwall.com/p/bzjuka/…
Connor Leech

як передавати дані між angular2 та jinja2? Будь-яка допомога
Нарендра

@Narendra - це інша проблема, не стосується цього питання. Будь ласка, знайдіть його, і якщо ви не знайдете відповіді, задайте це як нове запитання.
Ендофаг

Відповіді:


299

Для Angular 1.0 слід використовувати apis $ interpolateProvider для налаштування символів інтерполяції: http://docs.angularjs.org/api/ng.$interpolateProvider .

Щось подібне повинно зробити трюк:

myModule.config(function($interpolateProvider) {
  $interpolateProvider.startSymbol('{[{');
  $interpolateProvider.endSymbol('}]}');
});

Майте на увазі дві речі:

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

Хоча ми нічого не можемо зробити з першого питання, крім попередження людей, нам потрібно вирішити другий випуск.


4
Ви б не хотіли пояснити свій перший пункт (обслуговування, безпека та інші проблеми щодо змішування шаблонів на стороні сервера та клієнта)? Трохи більше пояснень було б корисно.
Брайан

1
@btlachance - я розширив відповідь.
Ігор Мінар

12
Оскільки $ interpolateProvider повертає себе при використанні в якості сеттера, ось дещо більш компактна версія: $interpolateProvider.startSymbol('{[{').endSymbol('}]}');
Марк Rajcok

5
Схоже, виправлення закрито. Чи означає це, що зараз не безпечно використовувати сторонні компоненти?
Олексій Окрушко

1
будь-який спосіб також оновити $ interpolateProvider для вихідної сировини? наприклад {{{foo}}} стає {{[{foo}]}}?
тестер

122

ви можете спробувати дослівно тег шаблону Django і використовувати його так:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>

{% verbatim %}
<div ng-app="">
    <p>10 is {{ 5 + 5 }}</p>
</div>
{% endverbatim %}


Хоча це дуже правильне рішення, є випадки, коли я хочу мати можливість завантажувати свої погляди на дані з сервера, щоб це швидко заплуталося. Подумайте, такі речі, як ім’я користувача, це не зміниться, тому я просто напишу його в шаблон на сервері, але навколо нього можуть бути фрагменти, які я напишу в кутовій формі.
Ендофаг

16
Дослівний є частиною основних тегів Django з версії 1.5: docs.djangoproject.com/en/dev/ref/templates/builtins/…
Пратюш

11
У Django 1.7 вам не потрібно завантажувати дослівно, оскільки це знаходиться у стандартній бібліотеці тегів. Потрібно лише використовувати самі теги.
хайпост

1
Було б непогано мати спосіб змінити дужки за замовчуванням Django з налаштувань, але це також працює.
Адріан Лопес

42

Якщо ви зробили окремі розділи сторінки належним чином, ви можете легко використовувати теги angularjs у "сирі" області тегів.

В jinja2

{% raw %}
    // here you can write angularjs template tags.
{% endraw %}

У шаблоні Джанго (вище 1,5)

{% verbatim %}    
    // here you can write angularjs template tags.
{% endverbatim %}

1
Це рішення не порушує сумісності, якщо зовнішні пакети не сприймають прийняту відповідь.
партизанос

30

Ми створили дуже простий фільтр у Django 'ng', який спрощує їх змішування:

foo.html:

...
<div>
  {{ django_context_var }}
  {{ 'angularScopeVar' | ng }}
  {{ 'angularScopeFunction()' | ng }}
</div>
...

ngФільтр виглядає наступним чином :

from django import template
from django.utils import safestring

register = template.Library()


@register.filter(name='ng')
def Angularify(value):
  return safestring.mark_safe('{{%s}}' % value)

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

1
Як створити фільтр ng? Чи можете ви додати приклад?
Бен Ліянаж

Оновлена ​​відповідь. @Endophage У мене набагато більше кутових {{}} пар, ніж у Django {{}} пар, тому я краще поновіть їх.
Уес Альваро

@WesAlvaro, на жаль, я можу прийняти лише одну відповідь.
Ендофаг

26

Тому я сьогодні отримав велику допомогу в каналі Angular IRC. Виявляється, ви можете дуже легко змінити теги шаблонів Angular. Необхідні фрагменти нижче повинні бути включені після того, як ваш кутовий включить (даний приклад відображається у їхніх списках розсилки та використовуватиметься (())як нові теги шаблону, замінюючи ваші власні):

angular.markup('(())', function(text, textNode, parentElement){
  if (parentElement[0].nodeName.toLowerCase() == 'script') return;
  text = text.replace(/\(\(/g,'{{').replace(/\)\)/g, '}}');
  textNode.text(text);
  return angular.markup('{{}}').call(this, text, textNode, parentElement);
});

angular.attrMarkup('(())', function(value, name, element){
    value = value.replace(/\(\(/g,'{{').replace(/\)\)/, '}}');
    element[0].setAttribute(name, value);
    return angular.attrMarkup('{{}}').call(this, value, name, element);
});

Крім того, мені було вказано на майбутнє вдосконалення, яке викриє startSymbolта endSymbolвластивості, які можна встановити на будь-які теги, які ви хочете.


17
і ось так ви це робите в angularjs 1.0: var m = angular.module ('myApp', []); m.config (функція ($ interpolateProvider) {$ interpolateProvider.startSymbol ('(('); $ interpolateProvider.endSymbol ('))');});
ідурсун

Кутовий канал IRC. я не знайшов когось, я знайшов його у #angularjs
Shanimal

17

Я голосую проти використання подвійних дужок (()) як тегів шаблонів. Це може спрацьовувати до тих пір, поки не задіяний жоден функціональний виклик, але коли спробували наступне

ng:disabled=(($invalidWidgets.visible()))

з Firefox (10.0.2) на Mac я отримав жахливо довгу помилку замість призначеної логіки. <[]> добре пішов для мене, принаймні, до цих пір.

Редагувати 2012-03-29: Зверніть увагу, що $ invalidWidgets застаріло. Однак я все-таки використовую іншу обгортку, ніж подвійні брекети. Для будь-якої кутової версії, що перевищує 0.10.7 (я думаю), ви можете змінити обгортку набагато простіше у своєму визначенні програми / модуля:

angular.module('YourAppName', [], function ($interpolateProvider) {
    $interpolateProvider.startSymbol('<[');
    $interpolateProvider.endSymbol(']>');
}); 

Документи API .


Справедливий пункт. Я не думав про це, але не особливо виступав за використання (()), я просто хотів мати можливість налаштувати роздільники.
Ендофаг

15

Я знайшов код нижче корисним. Я знайшов тут код: http://djangosnippets.org/snippets/2787/

"""
filename: angularjs.py

Usage:
    {% ng Some.angular.scope.content %}

e.g.
    {% load angularjs %}
    <div ng-init="yourName = 'foobar'">
        <p>{% ng yourName %}</p>
    </div>
"""

from django import template

register = template.Library()

class AngularJS(template.Node):
    def __init__(self, bits):
        self.ng = bits

    def render(self, ctx):
        return "{{%s}}" % " ".join(self.ng[1:])

def do_angular(parser, token):
    bits = token.split_contents()
    return AngularJS(bits)

register.tag('ng', do_angular)

Я використовував цей спеціальний тег, але тоді, якщо я використовую щось на кшталт: <p>{% ng location %}</p> він виводиться як {{location}}- так, з фігурними дужками! Це не надає значення $ range.location, яке жорстко кодується в моєму контролері. Будь-яка ідея, що мені не вистачає?
Кешав Агравал


11

Якщо ви використовуєте django 1.5 та новіші:

  {% verbatim %}
    {{if dying}}Still alive.{{/if}}
  {% endverbatim %}

Якщо ви застрягли з django 1.2 на appengine, розгорніть синтаксис django за допомогою команди дослівного шаблону на зразок цього…

from django import template

register = template.Library()

class VerbatimNode(template.Node):

    def __init__(self, text):
        self.text = text

    def render(self, context):
        return self.text

@register.tag
def verbatim(parser, token):
    text = []
    while 1:
        token = parser.tokens.pop(0)
        if token.contents == 'endverbatim':
            break
        if token.token_type == template.TOKEN_VAR:
            text.append('{{')
        elif token.token_type == template.TOKEN_BLOCK:
            text.append('{%')
        text.append(token.contents)
        if token.token_type == template.TOKEN_VAR:
            text.append('}}')
        elif token.token_type == template.TOKEN_BLOCK:
            text.append('%}')
    return VerbatimNode(''.join(text))

У використанні вашого файлу:

from google.appengine.ext.webapp import template
template.register_template_library('utilities.verbatim_template_tag')

Джерело: http://bamboobig.blogspot.co.at/2011/09/notebook-using-jquery-templates-in.html


Дякую ... нарешті це все спрацювало, але мені довелося ... 1) створити новий модуль Python. Я назвав його утилітами і помістив у нього файл verbatim_templatetag.py. (Файл вище, визначений у ньому клас VerbatimNode). 2) Змініть заяву про імпорт з: from django import template на: from google.appengine._internal.django import template Тоді в головному моєму файлі просто змінили ім'я файлу: template.register_template_library('utilities.verbatim_template_tag')
Роджер

7

Ви можете сказати Django для виведення {{та }}, а також інших зарезервованих рядків шаблону, використовуючи {% templatetag %}тег.

Наприклад, використання {% templatetag openvariable %}буде виводити {{.


3
Я знаю, що це можливо, але це безладно ... Це було б набагато чистіше (і не здається занадто великим запитом), щоб тег шаблону просто налаштовувався в одній із рам. Зрештою, це просто поєднання рядків за лаштунками ...
Endophage

3

Я б дотримувався рішення, яке використовує обидва теги django {{}}, а також angularjs {{}} або з дослівним розділом, або з шаблоном тегів.

Це просто тому, що ви можете змінити спосіб роботи angularjs (як уже згадувалося) за допомогою $ interpolateProvider.startSymbol $ interpolateProvider.endSymbol, але якщо ви почнете використовувати інші компоненти angularjs, такі як ui-bootstrap, ви побачите, що деякі шаблони ВЗАЄМО побудовані зі стандартними тегами angularjs {{}}.

Наприклад, подивіться на https://github.com/angular-ui/bootstrap/blob/master/template/dialog/message.html .


Гарна думка. Зараз у PyPI є пакет з джанго-кутом, який покликаний зробити їх двома хорошими разом, але я не розглядав, наскільки це полегшує проблему тегів шаблонів.
Ендофаг

0

Якщо ви робите будь-яку інтерполяцію на стороні сервера, єдиний правильний спосіб це зробити<>

$interpolateProvider.startSymbol('<{').endSymbol('}>');

Все інше - вектор XSS.

Це тому, що будь-які кутові обмежувачі, які не виходять Джанго, можуть бути введені користувачем у інтерпольовану рядок; якщо хтось встановить своє ім'я користувача як "{{evil_code}}", Angular із задоволенням запустить його . Якщо ви використовуєте персонаж, ніж Джанго тікає , однак це не відбудеться.

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