2012-01-14 52 views
5

Giả sử tôi có mã mẫu jinja thực tế trong biến X. Hãy để chúng tôi nói nội dung của X là "{{some_other_variable}}".Hiển thị lồng nhau của Jinja trên nội dung biến

Tôi làm cách nào để hiển thị X trong khi cũng hiển thị nội dung của nó?

ví dụ, điều này không làm việc:

{{X}}

Vì nó chỉ đơn giản là làm cho này để sàng lọc "{{some_other_variable}}" chứ không phải là nội dung của some_other_variable.

Lý do tôi làm theo cách này là tôi có một trang web trong đó (đáng tin cậy) người dùng có thể tạo các bài đăng có thể chứa mã mẫu jinja. Trang xem hiển thị các bài đăng này, nhưng do vấn đề ở trên, hiển thị chúng trực tiếp, thay vì thay thế các biến như tôi muốn.

+0

Added lời giải thích trên – muckabout

Trả lời

2

tôi không thể tìm thấy một cách tốt để làm vẽ lồng nhau này, tuy nhiên, tôi có thể cố gắng đề xuất một giải pháp thay thế:

Kể từ khi người dùng tạo ra các bài viết, tôi tưởng tượng "{{some_other_variable}}" là thực sự chuỗi con của toàn bộ bài đăng, cũng là một chuỗi.

tôi sẽ làm:

X.replace("{{some_other_variable}}", some_other_variable)) 

sau đó trở về {{X}} như bình thường. Điều đó có thỏa mãn điều bạn muốn làm không?

+0

Jinja2 thay thế sẽ tốt hơn một cái này. '{{X | thay thế (" {{Xin chào}} "," Tạm biệt ")}}' Tôi cần giải pháp bản địa nhiều hơn thế. –

+0

Tôi chắc chắn không phải là người có kinh nghiệm nhất trên mạng. Tôi sẽ vui mừng khi biết nếu có bất kỳ lý do cụ thể làm cho jinja2 thay thế tốt hơn. Ngoài ra, bạn có ý nghĩa gì bởi 'bản địa'? Như trong gần nhất với Jinja2 càng tốt? – nglinh

+0

oh vâng, tôi chắc chắn có nghĩa là gần nhất với Jinja2 nhất có thể. Tôi chỉ chờ đợi cho giải pháp chung chung hơn mà tôi có thể thêm toàn bộ khả năng jinja2 (không chỉ thay thế biến) trong các tình huống này. Nếu không, tôi sẽ cung cấp tiền thưởng để thay thế biến. –

2

Tôi nghĩ đến một cách thú vị để làm điều này:

  • Thiết lập một cuốn từ điển
  • Quấn một DictLoader xung quanh nó (nhưng giữ một tham chiếu vào từ điển xung quanh)
  • Vượt qua một chainloader với DictLoader và Trình tải bình thường của bạn vào môi trường
  • Triển khai bộ lọc tùy chỉnh bổ sung các thông số của nó vào từ điển đã nói ở trên
  • Sử dụng chỉ thị include cho c tất cả mã mẫu trong ngữ cảnh hiện tại

Chưa thử, nhưng nó có thể hoạt động!

+0

bộ lọc tùy chỉnh có thể làm bất cứ điều gì, thậm chí bạn không cần bước 1 đến 3. bạn có thể chuyển các biến thông qua jinja. Có cái gì khác mà sẽ xử lý thay thế các biến thông qua jinja chỉ không hướng dẫn như thế này. –

+0

Huh? Bộ lọc chỉ chuyển nội dung mẫu và đặt chúng vào từ điển mẫu để Jinja có thể xử lý chúng theo cách thông thường. Phần khó khăn là nhận bối cảnh của Jinja (để bạn có thể sử dụng nó để xử lý mẫu). Ngoài ra, tại sao bạn không muốn sử dụng bộ lọc tùy chỉnh? – djc

2

Tôi biết đó là một cuối :) chút nhưng đây là một giải pháp mà không ảnh hưởng đến mẫu mã:

import jinja2 
def recursive_render(tpl, values): 
    prev = tpl 
    while True: 
     curr = jinja2.Template(prev).render(**values) 
     if curr != prev: 
      prev = curr 
     else: 
      return curr 

Chạy thử:

>>> recursive_render("Hello {{X}}!", dict(X="{{name}}", name="world")) 
u'Hello world!' 

Lưu ý rằng đây không phải là rất hiệu quả, kể từ khi mẫu phải được reparsed từ đầu trên mỗi lần lặp.

0

Đây là những gì tôi đã đưa ra, bằng cách sử dụng tùy chọn finalize cho môi trường:

def render (tpl, args): 
    scope = {} 
    scope['env'] = jinja2.Environment (finalize=lambda x: scope['env'].from_string (x).render (**args) if isinstance(x, str) and '{{' in x else x) 
    scope['env'].filters['q'] = lambda value: re.sub (r'"', r'\\"', value) 
    return scope['env'].from_string (tpl).render (**args) 

Đó là một chút xấu xí, vì vậy cải thiện chào đón :)

Nhưng nó rendering đệ quy như OP đã yêu cầu và không dừng lại cho đến khi không còn {{ ở đầu ra ..

phiên Ví dụ

>>> import jinja2 
>>> def render (tpl, args): 
...   scope = {} 
...   scope['env'] = jinja2.Environment (finalize=lambda x: scope['env'].from_string (x).render (**args) if isinstance(x, str) and '{{' in x else x) 
...   scope['env'].filters['q'] = lambda value: re.sub (r'"', r'\\"', value) 
...   return scope['env'].from_string (tpl).render (**args) 
... 
>>> render("this {{ outer_var }} wokring!", {"outer_var":"{{ inner_var }}", "inner_var":"{{ final_step }}", "final_step":"is"}) 
u'this is wokring!' 

EDIT:

Ok, refactored tôi làm chức năng một chút, chức năng như nhau, nhưng một chút ngăn nắp:

def render (tpl, args): 
    @jinja2.environmentfunction 
    def finalize (env, value): 
     if isinstance(value, (str, unicode)) and '{{' in value: 
      return env.from_string (value).render (args) 
     return value 
    env = jinja2.Environment (finalize=finalize) 
    env.filters['q'] = lambda value: re.sub (r'"', r'\\"', value) 
    return env.from_string (tpl).render (args) 
0

Tôi tìm thấy một cách để làm việc với các tệp mẫu và các ảnh toàn cảnh môi trường.

def render(template, values): 
    prev = template.render(**values) 
    while True: 
     curr = Template(prev).render(siteinfo=config, menus=menus, blended_header=header, authors=authors, buildinfo=buildinfo, **values) 
     if curr != prev: 
      prev = curr 
     else: 
      return curr 

Trong phiên bản này, bạn phải chuyển toàn bộ môi trường đến hàm kết xuất bên trong chức năng này và chức năng tự nó nằm trong chức năng xây dựng của bạn.

Cách để gửi nội dung đó là: render(template, dict(content=post, tags=tags))

nơi template = env.get_template('index.html')

0

Tạo bộ lọc mới:

from jinja2 import contextfilter, Markup 

@contextfilter 
def subrender_filter(context, value): 
    _template = context.eval_ctx.environment.from_string(value) 
    result = _template.render(**context) 
    if context.eval_ctx.autoescape: 
     result = Markup(result) 
    return result 

env = Environment() 
env.filters['subrender'] = subrender_filter 

Và sau đó sử dụng nó trong mẫu:

{{ "Hello, {{name}}"|subrender }} 
Các vấn đề liên quan