AngularJS mit Django - Widersprüchliche Vorlagen-Tags


302

Ich möchte AngularJS mit Django verwenden, aber beide verwenden sie {{ }}als Vorlagen-Tags. Gibt es eine einfache Möglichkeit, eines der beiden zu ändern, um ein anderes benutzerdefiniertes Vorlagen-Tag zu verwenden?


1
Ich rendere nur eine Vorlage aus dem Django- templatesVerzeichnis, den Rest habe ich eingegeben static. Auf diese Weise haben Sie keine Störungen. Es gibt ein Tutorial, das ich hier geschrieben habe: coderwall.com/p/bzjuka/…
Connor Leech

Wie werden die Daten zwischen angle2 und jinja2 übergeben? Jede Hilfe
Narendra

@ Narendra das ist ein anderes Problem, das für diese Frage nicht relevant ist. Bitte suchen Sie danach und wenn Sie keine Antwort finden, stellen Sie sie als neue Frage.
Endophage

Antworten:


299

Für Angular 1.0 sollten Sie die Interpolationssymbole mit dem API $ interpolateProvider konfigurieren: http://docs.angularjs.org/api/ng.$interpolateProvider .

So etwas sollte den Trick machen:

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

Beachten Sie zwei Dinge:

  • Das Mischen von serverseitigen und clientseitigen Vorlagen ist selten eine gute Idee und sollte mit Vorsicht verwendet werden. Die Hauptprobleme sind: Wartbarkeit (schwer zu lesen) und Sicherheit (doppelte Interpolation könnte einen neuen Sicherheitsvektor verfügbar machen - z. B. wenn das Entkommen von serverseitigen und clientseitigen Vorlagen selbst sicher ist, ist ihre Kombination möglicherweise nicht sicher).
  • Wenn Sie Direktiven (Komponenten) von Drittanbietern verwenden, die {{ }}in ihren Vorlagen verwendet werden, werden diese durch Ihre Konfiguration beschädigt. ( Fix ausstehend )

Wir können zwar nichts gegen das erste Problem tun, außer Menschen zu warnen, aber wir müssen das zweite Problem angehen.


4
Würde es Ihnen etwas ausmachen, Ihren ersten Punkt zu erläutern (Wartung, Sicherheit und andere Probleme beim Mischen von serverseitigen und clientseitigen Vorlagen)? Eine etwas ausführlichere Erklärung wäre hilfreich.
Brian

1
@btlachance - Ich habe die Antwort erweitert.
Igor Minar

12
Da $ interpolateProvider als Setter selbst zurückgibt, ist hier eine etwas kompaktere Version: $interpolateProvider.startSymbol('{[{').endSymbol('}]}');
Mark Rajcok

5
Sieht aus wie das "Update" geschlossen ist. Bedeutet das, dass die Verwendung von Komponenten von Drittanbietern jetzt nicht sicher ist?
Alex Okrushko

1
Gibt es eine Möglichkeit, auch den $ interpolateProvider für die Rohausgabe zu aktualisieren? zB {{{foo}}} wird {{[{foo}]}}?
Tester

122

Sie können vielleicht versuchen, wörtlich Django Template Tag und verwenden Sie es wie folgt:

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


Dies ist zwar eine sehr gültige Lösung, aber es gibt Fälle, in denen ich meine Ansichten mit Daten vom Server booten möchte, damit dies schnell unübersichtlich wird. Denken Sie an Dinge wie den Benutzernamen des Benutzers, er wird sich nicht ändern, also schreibe ich ihn einfach in die Vorlage auf dem Server, aber es gibt möglicherweise Teile, die ich mit Winkel einschreiben werde.
Endophage

16
Verbatim ist Teil der Django-Kern-Tags seit Version 1.5: docs.djangoproject.com/de/dev/ref/templates/builtins/…
Pratyush

11
In Django 1.7 müssen Sie nicht wörtlich laden, da es sich in der Standard-Tag-Bibliothek befindet. Sie müssen nur die Tags selbst verwenden.
Highpost

1
Es wäre schön, eine Möglichkeit zu haben, die Django-Standardklammern in den Einstellungen zu ändern, aber das funktioniert auch.
Adrian Lopez

42

Wenn Sie Seitenabschnitte ordnungsgemäß getrennt haben, können Sie AngularJS-Tags problemlos im Bereich "Raw" -Tags verwenden.

In jinja2

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

In der Django-Vorlage (über 1.5)

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

1
Diese Lösung unterbricht nicht die Kompatibilität, wenn externe Pakete die akzeptierte Antwort enthalten.
Partizanos

30

Wir haben in Django 'ng' einen sehr einfachen Filter erstellt , der es einfach macht, beide zu mischen:

foo.html:

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

Der ngFilter sieht folgendermaßen aus:

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)

Ein weiterer sehr gültiger Weg, dies zu tun, aber ich würde lieber die Tags an einer Stelle ändern, als den Filter in vielen hinzuzufügen ...
Endophage

1
Wie erstellt man den ng-Filter? Können Sie ein Beispiel hinzufügen?
Ben Liyanage

Antwort aktualisiert. @Endophage Ich habe viel mehr Angular {{}} Paare als Django {{}} Paare, daher möchte ich lieber die Django-Paare aktualisieren.
Wes Alvaro

@WesAlvaro Leider kann ich nur eine Antwort akzeptieren.
Endophage

26

Deshalb habe ich heute im Angular IRC-Kanal große Hilfe bekommen. Es stellt sich heraus, dass Sie Angulars Vorlagen-Tags sehr einfach ändern können. Die erforderlichen Snippets unten sollten nach Ihrem eckigen Include enthalten sein (das angegebene Beispiel wird in den Mailinglisten angezeigt und (())als neue Vorlagen-Tags verwendet, die Ihre eigenen ersetzen):

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

Außerdem wurde ich auf eine bevorstehende Verbesserung hingewiesen, die verfügbar macht, startSymbolund endSymbolEigenschaften, die auf beliebige Tags eingestellt werden können.


17
und so machen Sie es in anglejs 1.0: var m = angular.module ('myApp', []); m.config (Funktion ($ interpolateProvider) {$ interpolateProvider.startSymbol ('(('); $ interpolateProvider.endSymbol ('))');});
Idursun

Winkel-IRC-Kanal. fwiw zu wem auch immer, ich fand eine bei #angularjs
Shanimal

17

Ich stimme gegen die Verwendung von doppelten Klammern (()) als Vorlagen-Tag. Es kann gut funktionieren, solange kein Funktionsaufruf beteiligt ist, aber wenn Folgendes versucht wird

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

Mit Firefox (10.0.2) auf dem Mac habe ich einen furchtbar langen Fehler anstelle der beabsichtigten Logik erhalten. <[]> ist mir zumindest bis jetzt gut gegangen.

Edit 2012-03-29: Bitte beachten Sie, dass $ invalidWidgets veraltet ist. Ich würde jedoch immer noch einen anderen Wrapper als Doppelklammern verwenden. Für jede Winkelversion höher als 0.10.7 (ich denke) können Sie den Wrapper in Ihrer App / Modul-Definition viel einfacher ändern:

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

API-Dokumente .


Gutes Argument. Daran hatte ich nicht gedacht, aber ich habe mich nicht besonders für die Verwendung ausgesprochen (()). Ich wollte nur die Trennzeichen konfigurieren können.
Endophage

15

Ich fand den folgenden Code hilfreich. Ich habe den Code hier gefunden: 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)

Ich habe dieses benutzerdefinierte Tag verwendet, aber wenn ich etwas wie Folgendes verwende: <p>{% ng location %}</p> Es wird gerendert als {{location}}- ja mit geschweiften Klammern! Der Wert von $ scope.location, der in meinem Controller fest codiert ist, wird nicht gerendert. Irgendeine Idee, was ich vermisse?
Keshav Agrawal


11

Wenn Sie Django 1.5 und höher verwenden, verwenden Sie:

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

Wenn Sie mit Django 1.2 auf Appengine nicht weiterkommen, erweitern Sie die Django-Syntax mit dem Befehl wörtliche Vorlage wie folgt ...

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

Verwenden Sie in Ihrer Datei:

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

Quelle: http://bamboobig.blogspot.co.at/2011/09/notebook-using-jquery-templates-in.html


Danke ... endlich hat das funktioniert, aber ich musste ... 1) ein neues Python-Modul erstellen. Ich habe es utilties genannt und die Datei verbatim_templatetag.py darin abgelegt. (Die obige Datei mit der darin definierten VerbatimNode-Klasse). 2) Ändern Sie die Importanweisung von: from django import template in: from google.appengine._internal.django import template Dann, in meiner Hauptdatei, ändern Sie einfach den Dateinamen: template.register_template_library('utilities.verbatim_template_tag')
Roger

7

Mit dem Tag können Sie Django anweisen, {{und }}andere reservierte Vorlagenzeichenfolgen auszugeben {% templatetag %}.

Zum Beispiel {% templatetag openvariable %}würde using ausgeben {{.


3
Ich weiß, dass das möglich ist, aber es ist chaotisch ... Es wäre viel sauberer (und scheint keine allzu große Frage zu sein), wenn das Template-Tag einfach in einem der Frameworks konfiguriert werden kann. Am Ende des Tages wird nur hinter den Kulissen ein String-Matching durchgeführt ...
Endophage

3

Ich würde mich an eine Lösung halten, die sowohl Django-Tags {{}} als auch Angularjs {{}} mit einem wörtlichen Abschnitt oder einem Templatetag verwendet.

Das liegt einfach daran, dass Sie die Funktionsweise von anglejs (wie erwähnt) über $ interpolateProvider.startSymbol $ interpolateProvider.endSymbol ändern können. Wenn Sie jedoch andere angularjs-Komponenten wie den UI-Bootstrap verwenden, werden Sie feststellen, dass einige der Vorlagen BEREITS erstellt wurden mit Standard-Angularjs-Tags {{}}.

Schauen Sie sich zum Beispiel https://github.com/angular-ui/bootstrap/blob/master/template/dialog/message.html an .


Guter Punkt. Es gibt jetzt ein Django-Angular-Paket in PyPI, mit dem die beiden gut zusammenspielen sollen, aber ich habe nicht untersucht, wie sehr es das Problem mit Vorlagen-Tags lindert.
Endophage

0

Wenn Sie eine serverseitige Interpolation durchführen, ist der einzig richtige Weg, dies zu tun<>

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

Alles andere ist ein XSS-Vektor.

Dies liegt daran, dass alle Winkelbegrenzer, die nicht von Django maskiert werden, vom Benutzer in die interpolierte Zeichenfolge eingegeben werden können. Wenn jemand seinen Benutzernamen auf "{{evil_code}}" setzt, führt Angular ihn gerne aus . Wenn Sie einen Charakter verwenden, dem Django entkommt , wird dies jedoch nicht passieren.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.