AngularJS与Django-冲突的模板标签


302

我想将AngularJS与Django一起使用,但是它们都{{ }}用作模板标记。有没有一种简单的方法可以将两者之一更改为使用其他自定义模板标签?


1
我只从django templates目录中渲染一个模板,其余的则放在static。这样,您就不会受到干扰。我在这里写了一个教程:coderwall.com/p/bzjuka/…–
Connor Leech,

如何在angular2和jinja2之间传递数据?任何帮助
-Narendra

@Narendra是一个与此问题无关的不同问题。请搜索它,如果找不到答案,请作为一个新问题提出。
Endophage

Answers:


299

对于Angular 1.0,您应该使用$ interpolateProvider API配置插值符号:http : //docs.angularjs.org/api/ng.$interpolateProvider

这样的事情应该可以解决问题:

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

请记住两件事:

  • 混合使用服务器端和客户端模板很少是一个好主意,应谨慎使用。主要问题是:可维护性(难于阅读)和安全性(双重插值可能会暴露出新的安全性向量-例如,虽然逃避服务器端和客户端模板可能是安全的,但结合起来可能并不安全)。
  • 如果您开始使用{{ }}在其模板中使用的第三方指令(组件),则您的配置将破坏它们。(修复中

尽管除了警告人们外,我们无法对第一个问题采取任何措施,但我们确实需要解决第二个问题。


4
您介意解释您的第一点(维护,安全以及混合服务器端和客户端模板的其他问题)吗?多一点解释会有所帮助。
布赖恩

1
@btlachance-我扩大了答案。
伊戈尔·塔纳

12
由于$ interpolateProvider用作设置器时会返回self,因此,它的版本稍微紧凑一些: $interpolateProvider.startSymbol('{[{').endSymbol('}]}');
Mark Rajcok 2012年

5
看起来“修复”已关闭。这是否意味着使用第三方组件并不安全?
Alex Okrushko

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
自1.5版以来,Verbatim是Django核心标签的一部分:docs.djangoproject.com/en/dev/ref/templates/builtins/…–
Pratyush

11
在Django 1.7中,您不需要加载逐字记录,因为它位于标准标记库中。您只需要自己使用标签。
高邮2014年

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 %}

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 2012年

1
您如何创建ng过滤器?你能添加一个例子吗?
Ben Liyanage 2014年

更新的答案。@Endophage我有很多更有棱角{{}}对,比我的Django {{}}对,所以我宁愿更新Django的人。
Wes Alvaro 2015年

不幸的是,@ WesAlvaro我只能接受一个答案。
Endophage 2015年

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);
});

另外,我还指出了即将发布的增强功能,该功能将公开startSymbolendSymbol可以设置为所需标签的属性。


17
这就是您在angularjs 1.0中执行的操作:var m = angular.module('myApp',[]); m.config(function($ interpolateProvider){$ interpolateProvider.startSymbol('(('); $ interpolateProvider.endSymbol('))');});
idursun 2012年

角度IRC通道。跟谁在一起,我在#angularjs
Shanimal 2012年

17

我反对使用双括号(())作为模板标记。只要不涉及任何函数调用,它就可能工作良好,但是在尝试以下操作时

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

在Mac上使用Firefox(10.0.2),我遇到了一个非常长的错误,而不是预期的逻辑。<[]>对我来说进展顺利,至少到现在为止。

编辑2012-03-29: 请注意,不建议使用$ invalidWidgets。但是,我仍然使用除双括号以外的其他包装器。对于任何高于0.10.7(我想)的角度版本,您可以在应用程序/模块定义中更轻松地更改包装器:

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

API文档


有道理。我没有想到这一点,但我并不是特别提倡使用(()),我只是想能够配置定界符。
Endophage 2012年

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的值。知道我想念什么吗?
Keshav Agrawal,2014年


11

如果您使用django 1.5及更高版本,请使用:

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

如果您在appengine上使用django 1.2感到困惑,请使用这样的逐字模板命令扩展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模块。我将其命名为utilities,并将文件verbatim_templatetag.py放入其中。(上面定义了VerbatimNode类的文件)。2)将导入语句从:更改 from django import template 为: from google.appengine._internal.django import template 然后,在我的主文件中,只需更改文件名: template.register_template_library('utilities.verbatim_template_tag')
罗杰(Roger)

7

您可以使用标记告诉Django输出{{}},以及其他保留的模板字符串{% templatetag %}

例如,使用{% templatetag openvariable %}will输出{{


3
我知道这是可能的,但很麻烦……将模板标记简单地配置在其中一个框架中会更加干净(而且要求不高)。归根结底,它只是在幕后进行字符串匹配……
Endophage

3

我会坚持使用一个Django标签{{}}以及带有逐字节或templatetag的angularjs {{}}的解决方案。

这仅仅是因为您可以通过$ interpolateProvider.startSymbol $ interpolateProvider.endSymbol来更改angularjs的工作方式(如上所述),但是如果您开始使用其他angularjs组件(如ui-bootstrap),则会发现某些模板已经构建带有标准angularjs标签{{}}。

例如,查看https://github.com/angular-ui/bootstrap/blob/master/template/dialog/message.html


好点子。PyPI中现在有一个django-angular软件包,旨在使两者完美地结合在一起,但是我没有研究它在多大程度上减轻了模板标签的问题。
Endophage

0

如果您进行任何服务器端插值,则唯一正确的方法是<>

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

其他都是XSS向量。

这是因为用户可以将任何未由Django进行转义的Angular分隔符输入到内插字符串中。如果有人将用户名设置为“ {{evil_code}}”,Angular会很乐意运行它。但是,如果您使用的字符不是Django转义符,则不会发生这种情况。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.