AngularJS กับ Django - แท็กแม่แบบที่ขัดแย้งกัน


302

ฉันต้องการใช้ AngularJS กับ Django ทั้งคู่ใช้{{ }}เป็นแท็กเทมเพลต มีวิธีง่ายๆในการเปลี่ยนหนึ่งในสองรายการนี้เพื่อใช้แท็กการสร้างเท็มเพลตแบบกำหนดเองอื่น ๆ หรือไม่?


1
ฉันเท่านั้นที่ทำให้แม่แบบจาก Django ไดเรกทอรีที่เหลือฉันใส่ในtemplates staticด้วยวิธีนี้คุณไม่มีการรบกวน มีแบบฝึกหัดที่ฉันเขียนไว้ที่นี่: coderwall.com/p/bzjuka/ …
Connor Leech

จะส่งข้อมูลระหว่าง angular2 และ jinja2 อย่างไร ความช่วยเหลือใด ๆ
Narendra

@ Narendra นั่นเป็นปัญหาอื่นที่ไม่เกี่ยวข้องกับคำถามนี้ โปรดค้นหาและหากคุณไม่พบคำตอบให้ถามเป็นคำถามใหม่
Endophage

คำตอบ:


299

สำหรับเชิงมุม 1.0 คุณควรใช้ $ interpolateProvider API เพื่อกำหนดค่าสัญลักษณ์การแก้ไข: http://docs.angularjs.org/api/ng.$interpolateProvider

สิ่งนี้ควรทำเคล็ดลับ:

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

โปรดทราบสองสิ่ง:

  • การผสมเทมเพลตฝั่งเซิร์ฟเวอร์และฝั่งไคลเอ็นต์ไม่ค่อยเป็นความคิดที่ดีและควรใช้ด้วยความระมัดระวัง ปัญหาหลักคือ: การบำรุงรักษา (อ่านยาก) และความปลอดภัย (การแก้ไขสองครั้งสามารถเปิดเผยเวกเตอร์ความปลอดภัยใหม่ - เช่นในขณะที่การหลบหนีจากฝั่งเซิร์ฟเวอร์และการสร้างแม่แบบไคลเอนต์ด้วยตัวเองอาจจะปลอดภัย
  • หากคุณเริ่มใช้คำสั่งของบุคคลที่สาม (ส่วนประกอบ) ที่ใช้{{ }}ในแม่แบบการกำหนดค่าของคุณจะทำให้แตก ( รอการแก้ไข )

ในขณะที่ไม่มีสิ่งใดที่เราสามารถทำได้เกี่ยวกับปัญหาแรกยกเว้นผู้เตือนเราจำเป็นต้องแก้ไขปัญหาที่สอง


4
คุณจะอธิบายจุดแรกของคุณ (การบำรุงรักษาความปลอดภัยและความกังวลอื่น ๆ สำหรับการผสมแม่แบบฝั่งเซิร์ฟเวอร์และฝั่งไคลเอ็นต์) คำอธิบายเพิ่มเติมเล็กน้อยจะเป็นประโยชน์
Brian

1
@btlachance - ฉันขยายคำตอบ
Igor Minar

12
เนื่องจาก $ interpolateProvider ส่งคืนตนเองเมื่อใช้เป็น setter ต่อไปนี้เป็นรุ่นที่กะทัดรัดกว่าเล็กน้อย: $interpolateProvider.startSymbol('{[{').endSymbol('}]}');
Mark 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 %}


ในขณะที่เป็นวิธีการแก้ปัญหาที่ถูกต้องมากมีหลายกรณีที่ฉันต้องการที่จะสามารถบูตการดูของฉันด้วยข้อมูลจากเซิร์ฟเวอร์เพื่อให้สิ่งนี้ยุ่งเหยิงเร็ว คิดเหมือนชื่อผู้ใช้ของผู้ใช้มันจะไม่เปลี่ยนแปลงดังนั้นฉันจะเขียนลงในเทมเพลตที่เซิร์ฟเวอร์ แต่อาจมีบางส่วนที่ฉันจะเขียนด้วยเชิงมุม
Endophage

16
คำต่อคำเป็นส่วนหนึ่งของแท็กหลักของ Django ตั้งแต่รุ่น 1.5: docs.djangoproject.com/en/dev/ref/templates/builtins/…
Pratyush

11
ใน Django 1.7 คุณไม่จำเป็นต้องโหลดคำต่อคำเนื่องจากอยู่ในไลบรารีแท็กมาตรฐาน คุณต้องใช้แท็กเองเท่านั้น
highpost

1
เป็นเรื่องดีที่มีวิธีเปลี่ยนวงเล็บเริ่มต้นของ Django จากการตั้งค่า แต่ก็ใช้ได้เช่นกัน
Adrian Lopez

42

หากคุณแยกส่วนของหน้าอย่างเหมาะสมคุณสามารถใช้แท็ก angularjs ในขอบเขตแท็ก "raw" ได้อย่างง่ายดาย

ใน 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

1
คุณจะสร้างตัวกรอง ng ได้อย่างไร คุณสามารถเพิ่มตัวอย่างได้หรือไม่
Ben Liyanage

อัปเดตคำตอบ @Endophage ฉันมีจำนวนมากมากขึ้นเชิงมุม {{}} คู่กว่าที่ฉันมี Django {{}} คู่ดังนั้นผมจึงอยากจะอัปเดตคน Django
Wes Alvaro

@WesAlvaro โชคไม่ดีที่ฉันสามารถตอบได้เพียงคำตอบเดียว
Endophage

26

ดังนั้นฉันจึงได้รับความช่วยเหลือที่ดีในช่อง IRC ของ Angular วันนี้ ปรากฎว่าคุณสามารถเปลี่ยนแท็กแม่แบบของ 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คุณสมบัติที่สามารถตั้งค่าเป็นแท็กที่คุณต้องการ


17
และนี่คือวิธีที่คุณทำใน angularjs 1.0: var m = angular.module ('myApp', []); m.config (ฟังก์ชั่น ($ interpolateProvider) {$ interpolateProvider.startSymbol ('(('); $ interpolateProvider.endSymbol ('))');});
idursun

IRC เชิงมุม fwiw ถึงใครก็ตามที่ฉันพบหนึ่งที่ #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


จุดยุติธรรม ฉันไม่ได้คิดอย่างนั้น แต่ฉันไม่ได้สนับสนุนการใช้โดยเฉพาะ(())ฉันแค่อยากจะกำหนดค่าตัวคั่น
Endophage

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 ซึ่ง hardcoded ในตัวควบคุมของฉัน ความคิดใดที่ฉันหายไป?
Keshav Agrawal


11

ถ้าคุณใช้ django 1.5 และใหม่กว่าใช้:

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

หากคุณติดกับ django 1.2 ใน appengine ให้ขยาย django syntax ด้วยคำสั่ง 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 ใหม่ ฉันตั้งชื่อมันว่า 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
ฉันรู้ว่ามันเป็นไปได้ แต่มันยุ่งเหยิง ... มันจะสะอาดกว่า (และดูเหมือนว่าจะไม่ใหญ่เกินไป) สำหรับแท็กเทมเพลตที่สามารถกำหนดค่าได้ในกรอบใดกรอบหนึ่ง ในตอนท้ายของวันมันเป็นเพียงการจับคู่สตริงที่อยู่เบื้องหลัง ...
Endophage

3

ฉันจะยึดติดกับโซลูชันที่ใช้แท็ก django ทั้ง {{}} และ angularjs {{}} ด้วยส่วนคำต่อคำหรือเทมเพลตแท็ก

นั่นเป็นเพียงเพราะคุณสามารถเปลี่ยนวิธีการทำงานของ angularjs (ดังที่กล่าวไว้) ผ่านทาง $ interpolateProvider.startSymbol $ interpolateProvider.endSymbol แต่ถ้าคุณเริ่มใช้ส่วนประกอบ angularjs อื่น ๆ เช่น ui-bootstrap คุณจะพบว่าเทมเพลตบางตัวเป็นแบบ ALREADY ด้วยแท็ก angularjs มาตรฐาน {{}}

ยกตัวอย่างเช่นดูที่https://github.com/angular-ui/bootstrap/blob/master/template/dialog/message.html


จุดดี. ขณะนี้มีแพคเกจ django-angular ใน PyPI ที่ทำให้การเล่นทั้งสองร่วมกันนั้นดี แต่ฉันไม่ได้ดูว่ามันช่วยบรรเทาปัญหาเทมเพลตแท็กได้มากน้อยเพียงใด
Endophage

0

ถ้าคุณทำสิ่งใดแก้ไขฝั่งเซิร์ฟเวอร์ที่เพียงวิธีที่ถูกต้องที่จะทำนี้ด้วย<>

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

สิ่งอื่นใดคือเวกเตอร์ XSS

นี่เป็นเพราะตัวคั่นเชิงมุมใด ๆ ที่ไม่ได้หลบหนีจาก Django สามารถป้อนได้โดยผู้ใช้ในสตริงที่ถูกแทรกเข้าไป ถ้ามีคนกำหนดชื่อผู้ใช้ของพวกเขาเป็น "{{}} evil_code" เชิงมุมจะมีความสุขเรียกใช้ หากคุณใช้ตัวละครที่ดีกว่า Django หนีออกมาสิ่งนี้จะไม่เกิดขึ้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.