AngularJSとDjango-競合するテンプレートタグ


302

AngularJSをDjangoで使用したいのですが、どちらも{{ }}テンプレートタグとして使用しています。他のカスタムテンプレートタグを使用するように2つのうちの1つを変更する簡単な方法はありますか?


1
私はdjango templatesディレクトリから1つのテンプレートのみをレンダリングし、残りは私が入れましたstatic。そうすれば、干渉を受けることがありません。私がここに書いたチュートリアルがあります:coderwall.com/p/bzjuka/...は
コナーリーチ

angular2とjinja2の間でデータを渡す方法は?任意のヘルプ
Narendra 2017年

@ナレンドラは、この質問には関係のない別の問題です。検索してください。答えが見つからない場合は、新しい質問として質問してください。
エンドファージ2017年

回答:


299

Angular 1.0の場合、$ interpolateProvider apisを使用して補間シンボルを構成する必要があります:http : //docs.angularjs.org/api/ng.$interpolateProvider

このようなことがうまくいくはずです:

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

次の2つの点に注意してください。

  • サーバー側のテンプレートとクライアント側のテンプレートを混在させることはめったにないので、注意して使用する必要があります。主な問題は次のとおりです。保守性(読みにくい)とセキュリティ(二重補間は新しいセキュリティベクトルを公開する可能性があります-たとえば、サーバーサイドとクライアントサイドのテンプレートのエスケープは安全であるかもしれませんが、それらの組み合わせは安全ではないかもしれません)。
  • {{ }}テンプレートで使用するサードパーティのディレクティブ(コンポーネント)の使用を開始すると、構成によってそれらが破壊されます。(修正保留中

最初の問題については、警告する人以外は何もできませんが、2番目の問題に対処する必要があります。


4
最初のポイント(メンテナンス、セキュリティ、およびサーバー側とクライアント側のテンプレートを混在させることに関するその他の懸念)を説明してもらえますか?もう少し説明が役に立ちます。
ブライアン

1
@btlachance-私は答えを拡大しました。
イゴールミナー

12
セッターとして使用した場合$ interpolateProviderが自己を返すので、ここで少しよりコンパクトなバージョンがあります: $interpolateProvider.startSymbol('{[{').endSymbol('}]}');
マーク・Rajcok

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以降のDjangoコアタグの一部である:docs.djangoproject.com/en/dev/ref/templates/builtins/...
Pratyush

11
Django 1.7では、標準のタグライブラリにあるため、逐語的にロードする必要はありません。タグ自体を使用するだけで済みます。
ハイポスト2014年

1
Djangoのデフォルトのブラケットを設定から変更する方法があると便利ですが、これも機能します。
エイドリアンロペス

42

ページのセクションを適切に分離した場合、 "raw"タグのスコープで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'で2つを簡単に組み合わせることができる非常にシンプルなフィルターを作成しました。

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)

別の非常に有効な方法ですが、多くの場所でフィルターを追加するよりも、1か所でタグを変更したいのです...
エンドファージ

1
どのようにngフィルターを作成しますか?例を追加できますか?
Ben Liyanage、2014

回答を更新しました。私が持っている@Endophage 多く、私はむしろ、Djangoのものを更新したいので、私は、Djangoの{{}}のペアを持っているよりも多くの角度{{}}のペアを。
Wes Alvaro、

@WesAlvaro残念ながら1つの回答しか受け付けません。
エンドファージ、

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年

Angular IRCチャネル。誰にでもfwiw、私は#angularjsで1つ見つけました
Shanimal

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ドキュメント


フェアポイント。私はそのことを考えていませんでしたが(())、を使用することを特に主張していませんでした。区切り文字を構成できるようにしたかっただけです。
エンドファージ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モジュールを作成します。私はそれにutiltiesという名前を付け、それに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 %}するとが出力されます{{


3
私はそれが可能であることを知っていますが、それは厄介です...テンプレートタグをフレームワークの1つで単に構成できるようにすることは、はるかにクリーンになります(そして、大きすぎる質問ではないようです)。結局のところ、それは舞台裏で文字列照合をしているだけです...
エンドファージ

3

私は、djangoタグ{{}}とangularjs {{}}の両方を逐語的セクションまたはテンプレートタグで使用するソリューションを使い続けます。

これは、$ interpolateProvider.startSymbol $ interpolateProvider.endSymbolを介してangularjsの動作を(前述のように)変更できるためですが、ui-bootstrapなどの他のangularjsコンポーネントの使用を開始すると、一部のテンプレートが既に構築されていることがわかります標準のangularjsタグ{{}}を使用します。

たとえば、https://github.com/angular-ui/bootstrap/blob/master/template/dialog/message.htmlをご覧ください


いい視点ね。PyPIにはdjango-angularパッケージがあり、2つを連携させることを目的としていますが、テンプレートタグの問題をどの程度軽減するかについてはまだ調べていません。
エンドファージ2013年

0

サーバー側の補間を行う場合、これを行う唯一の正しい方法は<>

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

それ以外はXSSベクトルです。

これは、DjangoによってエスケープされないAngular区切り文字が、ユーザーが補間文字列に入力できるためです。ユーザー名が「{{evil_code}}」に設定されている場合、Angularはそれを喜んで実行します。ただし、Djangoがエスケープする文字以外文字を使用すると、これは起こりません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.