渲染Jinja2模板后,是否可以获取设置值?

After rendering a Jinja2 template, can I get the set values?

我想渲染一个Jinja2模板,渲染后读取它设置的值:

import jinja2

template = jinja2.Template("""
    {% set number = 42 %}
    Hello {{name}} {{number}}!
    """)

vars = {"name": "Ned"}
print(template.render(vars).strip())
print(vars)

这会打印:

Hello Ned 42!
{'name': 'Ned'}

template.render 之后我可以做些什么来获得 number 的价值?另外,我需要在事先不知道名字 number 的情况下进行。我想发现模板中设置的任何值。

根据提供的上下文:

import jinja2
import re

template = jinja2.Template("""
    {% set number = 42 %}
    Hello {{name}} {{number}}!
    """)

vars = {"name": "Ned"}
rendered = template.render(vars).strip()
print(vars)
print(rendered)
changed_var_value = re.findall(r'Hello[\s\S]*\s{1}(.*)!', rendered)
print(f'var after the greeting: {changed_var_value}')

输出:

{'name': 'Ned'}
Hello Ned 42!
var after the greeting: ['42']

我想,这有点骇人听闻,但您似乎可以使用 jinja2.runtime 中的 Context 做一些事情,例如

$ cat show_vars.py
import jinja2

template = jinja2.Template("""
    {% set number = 42 %}
    Hello {{name}} {{number}}!
    """)

vars = {"name": "Ned"}
print(template.render(vars).strip())
print(vars)

from jinja2 import Environment
from jinja2.runtime import Context

env = Environment()

ctx = Context(env, vars, '', template.blocks)
list(template.root_render_func(ctx))
print(ctx.vars)
print(ctx.get_all())

$ python show_vars.py
Hello Ned 42!
{'name': 'Ned'}
{'number': 42}
{'name': 'Ned', 'number': 42}

正如@nedbat指出的那样,也可以用

达到同样的效果
import jinja2

template = jinja2.Template("""
    {% set number = 42 %}
    Hello {{name}} {{number}}!
    {% if number > 50 %}
        More than 40!
        {% set also = 'foo' %}
    {% endif %}
    """)

ctx = template.new_context(vars = {"name": "Ned"})
list(template.root_render_func(ctx))
print("get_all:", ctx.get_all())
print("exported_vars:", ctx.exported_vars)
print("vars:", ctx.vars)

这是一种不使用记录在案但不使用它们的函数的方法:

import jinja2

template = jinja2.Template("""
    {% set number = 52 %}
    {% set choice = "apple" %}
    Hello {{name}} {{number}}!
    {% if number > 50 %}
        More than 40!
        {% set also = 'foo' %}
    {% endif %}
    """)

ctx = template.new_context(vars = {"name": "Ned"})
template.render(ctx)
mod = template.module
template_vars = {n:getattr(mod, n) for n in dir(mod) if not n.startswith("_")}
print(template_vars)

这会打印:

{'also': 'foo', 'choice': 'apple', 'number': 52}