AngularJS với Django - Thẻ mẫu xung đột


302

Tôi muốn sử dụng AngularJS với Django tuy nhiên cả hai đều sử dụng {{ }}làm thẻ mẫu. Có cách nào dễ dàng để thay đổi một trong hai để sử dụng một số thẻ tạo mẫu tùy chỉnh khác không?


1
Tôi chỉ kết xuất một mẫu từ templatesthư mục django , phần còn lại tôi đặt vào static. Bằng cách đó bạn không bị nhiễu. Có một hướng dẫn tôi đã viết ở đây: coderwall.com/p/bzjuka/ Kẻ
Connor Leech

Làm thế nào để truyền dữ liệu giữa angular2 và jinja2? Bất kỳ trợ giúp
Narendra

@Narendra đó là một vấn đề khác không liên quan đến câu hỏi này. Vui lòng tìm kiếm nó và nếu bạn không tìm thấy câu trả lời, hãy hỏi nó như một câu hỏi mới.
Endophage

Câu trả lời:


299

Đối với Angular 1.0, bạn nên sử dụng apis $ interpolateProvider để định cấu hình các ký hiệu nội suy: http://docs.angularjs.org/api/ng.$interpolateProvider .

Một cái gì đó như thế này nên thực hiện các mẹo:

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

Hãy ghi nhớ hai điều:

  • trộn các mẫu phía máy chủ và phía máy khách hiếm khi là một ý tưởng hay và nên được sử dụng một cách thận trọng. Các vấn đề chính là: khả năng bảo trì (khó đọc) và bảo mật (phép nội suy kép có thể làm lộ ra một vectơ bảo mật mới - ví dụ: trong khi thoát khỏi máy chủ và khuôn mẫu của máy khách có thể được bảo mật, sự kết hợp của chúng có thể không được).
  • nếu bạn bắt đầu sử dụng các chỉ thị (thành phần) của bên thứ ba sử dụng {{ }}trong các mẫu của họ thì cấu hình của bạn sẽ phá vỡ chúng. ( đang chờ xử lý )

Mặc dù không có gì chúng tôi có thể làm về vấn đề đầu tiên, ngoại trừ cảnh báo mọi người, chúng tôi cần phải giải quyết vấn đề thứ hai.


4
Bạn có phiền giải thích điểm đầu tiên của bạn (bảo trì, bảo mật và các mối quan tâm khác để trộn các mẫu phía máy chủ và phía máy khách) không? Một chút giải thích sẽ hữu ích.
Brian

1
@btlachance - Tôi mở rộng câu trả lời.
Igor Minar

12
Vì $ interpolateProvider tự trả về khi được sử dụng làm setter, nên đây là phiên bản nhỏ gọn hơn một chút: $interpolateProvider.startSymbol('{[{').endSymbol('}]}');
Mark Rajcok

5
Có vẻ như "sửa chữa" đã bị đóng. Điều đó có nghĩa là bây giờ không an toàn khi sử dụng các thành phần của bên thứ ba?
Alex Okrushko

1
có cách nào để cập nhật $ interpolateProvider cho đầu ra thô không? ví dụ: {{{foo}}} trở thành {{[{foo}]}}?
người kiểm tra

122

bạn có thể thử nguyên mẫu thẻ Django và sử dụng nó như thế này:

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


Mặc dù đó là một giải pháp rất hợp lệ, có những trường hợp tôi muốn có thể tự khởi động lại các quan điểm của mình bằng dữ liệu từ máy chủ để việc này trở nên lộn xộn nhanh chóng. Hãy nghĩ những thứ như tên người dùng của người dùng, nó sẽ không thay đổi, vì vậy tôi sẽ chỉ viết nó vào mẫu tại máy chủ nhưng có thể có những mảnh xung quanh nó mà tôi sẽ viết với góc cạnh.
Endophage

16
Verbatim là một phần của thẻ lõi Django kể từ phiên bản 1.5: docs.djangoproject.com/en/dev/ref/temsheet/builtins/ trộm
Pratyush

11
Trong Django 1.7, bạn không cần tải nguyên văn vì nó nằm trong thư viện thẻ tiêu chuẩn. Bạn chỉ cần sử dụng các thẻ chính mình.
highpost

1
Sẽ rất tuyệt nếu có cách thay đổi dấu ngoặc mặc định của Django từ cài đặt, nhưng điều này cũng hoạt động.
Adrian Lopez

42

Nếu bạn đã tách riêng các phần của trang một cách chính xác thì bạn có thể dễ dàng sử dụng các thẻ angularjs trong phạm vi thẻ "thô".

Trong jinja2

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

Trong mẫu Django (trên 1,5)

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

1
Giải pháp này không phá vỡ tính tương thích trong các gói bên ngoài là câu trả lời được chấp nhận.
partizanos

30

Chúng tôi đã tạo một bộ lọc rất đơn giản trong Django 'ng' để giúp dễ dàng kết hợp cả hai:

foo.html:

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

Bộ nglọc trông như thế này:

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)

Một cách rất hợp lệ khác để làm điều đó, tuy nhiên tôi muốn thay đổi các thẻ ở một nơi hơn là thêm bộ lọc vào nhiều ...
Endophage

1
Làm thế nào để bạn tạo bộ lọc ng? Bạn có thể thêm một ví dụ?
Ben Liyanage

Cập nhật câu trả lời. @Endophage Tôi có nhiều cặp {{}} Angular hơn nhiều so với các cặp Django {{}}, vì vậy tôi muốn cập nhật các cặp Django.
Wes Alvaro

@WesAlvaro thật không may, tôi chỉ có thể chấp nhận một câu trả lời.
Endophage

26

Vì vậy, tôi đã nhận được một số trợ giúp tuyệt vời trong kênh Angular IRC ngày hôm nay. Hóa ra bạn có thể thay đổi thẻ mẫu của Angular rất dễ dàng. Các đoạn cần thiết dưới đây nên được đưa vào sau góc bao gồm của bạn (ví dụ đã cho xuất hiện trong danh sách gửi thư của họ và sẽ sử dụng (())làm thẻ mẫu mới, thay thế cho thẻ của bạn):

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

Ngoài ra, tôi đã được chỉ ra một cải tiến sắp tới sẽ phơi bày startSymbolendSymbolcác thuộc tính có thể được đặt thành bất kỳ thẻ nào bạn muốn.


17
và đây là cách bạn làm điều đó trong angularjs 1.0: var m = angular.module ('myApp', []); m.config (function ($ interpolateProvider) {$ interpolateProvider.startSymbol ('(('); $ interpolateProvider.endSymbol ('))');});
idursun

Kênh IRC góc. fwiw cho bất cứ ai, tôi tìm thấy một tại #angularjs
Shanimal

17

Tôi bỏ phiếu không sử dụng dấu ngoặc đơn (()) làm thẻ mẫu. Nó có thể hoạt động tốt miễn là không có chức năng gọi nhưng khi thử các cách sau

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

với Firefox (10.0.2) trên Mac, tôi đã gặp một lỗi rất dài thay vì logic dự định. <[]> đã tốt cho tôi, ít nhất là cho đến bây giờ.

Chỉnh sửa 2012-03-29: Xin lưu ý rằng $ không hợp lệWidgets không được chấp nhận. Tuy nhiên tôi vẫn sử dụng một trình bao bọc khác ngoài niềng răng đôi. Đối với bất kỳ phiên bản góc nào cao hơn 0.10.7 (tôi đoán), bạn có thể thay đổi trình bao bọc dễ dàng hơn rất nhiều trong định nghĩa ứng dụng / mô-đun của bạn:

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

Tài liệu API .


Điểm công bằng. Tôi đã không nghĩ về điều đó nhưng tôi không đặc biệt ủng hộ việc sử dụng (()), tôi chỉ muốn có thể định cấu hình các dấu phân cách.
Endophage

15

Tôi tìm thấy mã dưới đây hữu ích. Tôi tìm thấy mã ở đây: 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)

Tôi đã sử dụng thẻ tùy chỉnh này nhưng sau đó nếu tôi sử dụng một cái gì đó như: <p>{% ng location %}</p> nó được hiển thị dưới dạng {{location}}- có với dấu ngoặc nhọn! Nó không hiển thị giá trị của $ scope.location, được mã hóa cứng trong bộ điều khiển của tôi. Có ai biết tôi đang thiếu gì không?
Keshav Agrawal


11

Nếu bạn sử dụng django 1.5 và mới hơn, hãy sử dụng:

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

Nếu bạn bị mắc kẹt với django 1.2 trên appengine, hãy mở rộng cú pháp django bằng lệnh nguyên văn như thế này ...

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

Trong tập tin của bạn sử dụng:

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

Nguồn: http://blynbig.blogspot.co.at/2011/09/notebook-USE-jquery-tem mẫu-in.html


Cảm ơn ... cuối cùng đã làm việc này nhưng tôi phải ... 1) tạo mô-đun Python mới. Tôi đặt tên cho nó là utilties và đặt tệp verbatim_templatetag.py trong đó. (Tệp ở trên với lớp VerbatimNode được xác định trong đó). 2) Thay đổi câu lệnh nhập từ: from django import template thành: from google.appengine._internal.django import template Sau đó, trong tệp chính của tôi, chỉ cần thay đổi tên tệp: template.register_template_library('utilities.verbatim_template_tag')
Roger

7

Bạn có thể yêu cầu Django xuất {{}}, cũng như các chuỗi mẫu dành riêng khác bằng cách sử dụng {% templatetag %}thẻ.

Ví dụ, sử dụng {% templatetag openvariable %}sẽ xuất ra {{.


3
Tôi biết điều đó là có thể nhưng nó lộn xộn ... Nó sẽ sạch hơn nhiều (và dường như không phải là một câu hỏi quá lớn) để thẻ mẫu có thể được cấu hình đơn giản trong một trong các khung. Vào cuối ngày nó chỉ làm phù hợp với chuỗi đằng sau hậu trường ...
Endophage

3

Tôi sẽ gắn bó với một giải pháp sử dụng cả hai thẻ django {{}} cũng như angularjs {{}} với một phần nguyên văn hoặc templatetag.

Điều đó đơn giản là vì bạn có thể thay đổi cách thức hoạt động của angularjs (như đã đề cập) thông qua $ interpolateProvider.startSymbol $ interpolateProvider.endSymbol nhưng nếu bạn bắt đầu sử dụng các thành phần angularjs khác như ui-bootstrap, bạn sẽ thấy rằng một số mẫu được tạo ra như vậy. với các thẻ angularjs tiêu chuẩn {{}}.

Ví dụ: hãy xem https://github.com/angular-ui/bootstrap/blob/master/template/dialog/message.html .


Điểm tốt. Hiện tại có một gói django-angular trong PyPI có nghĩa là làm cho hai người chơi tốt với nhau, nhưng tôi chưa nhìn vào việc nó làm giảm bớt vấn đề thẻ mẫu như thế nào.
Endophage

0

Nếu bạn thực hiện bất kỳ phép nội suy phía máy chủ nào, cách duy nhất đúng để thực hiện việc này là với<>

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

Bất cứ điều gì khác là một vector XSS.

Điều này là do bất kỳ dấu phân cách góc nào không được Django thoát ra đều có thể được người dùng nhập vào chuỗi nội suy; nếu ai đó đặt tên người dùng của họ là "{{evil_code}}", Angular sẽ vui vẻ chạy nó . Tuy nhiên, nếu bạn sử dụng một nhân vật hơn Django trốn thoát , điều này sẽ không xảy ra.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.