AngularJS с Django - конфликтующие теги шаблонов

302

Я хочу использовать AngularJS с Django, однако они оба используют в {{ }}качестве тегов своих шаблонов. Есть ли простой способ изменить один из двух, чтобы использовать какой-либо другой пользовательский шаблонный тег?

Endophage
источник
1
Я рендеринг только один шаблон из templatesкаталога Django , остальные я положил в static. Таким образом, у вас нет помех. Вот учебник, который я написал здесь: coderwall.com/p/bzjuka/…
Коннор Лич
как передать данные между angular2 и jinja2? Любая помощь
Нарендра
@ Нарендра, это другая проблема, не относящаяся к этому вопросу. Пожалуйста, найдите его, и если вы не нашли ответа, задайте его как новый вопрос.
Эндофаг

Ответы:

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 возвращает self при использовании в качестве установщика, вот немного более компактная версия: $interpolateProvider.startSymbol('{[{').endSymbol('}]}');
Марк Райкок
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 %}

Бессуфи Мунир
источник
Несмотря на то, что это очень правильное решение, в некоторых случаях я хочу иметь возможность загружать свои представления с данных с сервера, чтобы это быстро запуталось. Подумайте, как имя пользователя, оно не изменится, поэтому я просто напишу его в шаблоне на сервере, но могут быть кусочки вокруг, которые я напишу с помощью angular.
Эндофаг
16
Verbatim является частью основных тегов Django начиная с версии 1.5: docs.djangoproject.com/en/dev/ref/templates/builtins/…
Pratyush
11
В Django 1.7 вам не нужно загружать дословно, поскольку он находится в стандартной библиотеке тегов. Вам нужно только использовать сами теги.
высокий пост
1
Было бы неплохо иметь способ изменить скобки Django по умолчанию из настроек, но это тоже работает.
Адриан Лопес
42

Если вы правильно сделали отдельные разделы страницы, то вы можете легко использовать теги angularjs в области «необработанных» тегов.

В jinja2

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

В шаблоне Django (выше 1.5)

{% verbatim %}    
    // here you can write angularjs template tags.
{% endverbatim %}
thanksnote
источник
1
Это решение не нарушает совместимость внешних пакетов с принятым ответом.
partizanos
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
Как вы создаете фильтр нг? Можете ли вы добавить пример?
Бен Лиянэйдж
Обновленный ответ. @ Endofhage У меня намного больше пар Angular {{}}, чем у пар Django {{}}, поэтому я бы лучше обновил пары 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свойства, которые могут быть установлены для любых тегов, которые вы хотите.

Endophage
источник
17
и вот как вы делаете это в angularjs 1.0: var m = angular.module ('myApp', []); m.config (function ($ interpolateProvider) {$ interpolateProvider.startSymbol ('(('); $ interpolateProvider.endSymbol ('))');});
idursun
Угловой канал 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}}- да с фигурными скобками! Он не отображает значение $ scope.location, которое жестко задано в моем контроллере. Есть идеи, что мне не хватает?
Кешав Агравал
11

Если вы используете django 1.5 и новее, используйте:

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

Если вы застряли с django 1.2 в appengine, расширьте синтаксис django командой verbatim template следующим образом ...

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
Я знаю, что это возможно, но это грязно ... Было бы намного чище (и не кажется слишком большой просьбой), чтобы тег шаблона просто настраивался в одной из платформ. В конце дня он просто выполняет струнное сопоставление за кулисами ...
Эндофаг
3

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

Это просто потому, что вы можете изменить способ работы angularjs (как уже упоминалось) с помощью $ interpolateProvider.startSymbol $ interpolateProvider.endSymbol, но если вы начнете использовать другие компоненты angularjs, такие как ui-bootstrap, вы обнаружите, что некоторые шаблоны уже построены со стандартными тегами angularjs {{}}.

Например, посмотрите на https://github.com/angular-ui/bootstrap/blob/master/template/dialog/message.html .

silviud
источник
Хорошая точка зрения. Теперь в PyPI есть пакет django-angular, предназначенный для того, чтобы они оба играли вместе, но я не изучал, насколько это облегчает проблему с тегами шаблонов.
Эндофаг
0

Если вы делаете какую-либо серверную интерполяцию, единственный правильный способ сделать это с<>

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

Все остальное является вектором XSS.

Это происходит потому, что любые угловые разделители, которые не экранированы Django, могут быть введены пользователем в интерполированную строку; если кто-то установит свое имя пользователя как "{{evil_code}}", Angular с удовольствием его запустит . Если вы используете персонажа, то Django убегает , однако этого не произойдет.

Дэн
источник