如何从Jinja2模板获取所有未定义的变量?

mot*_*oth 2 python jinja2 flask

我试图从Jinja2模板中获取所有未定义的变量。假设我有如下模板。

tmpstr = """
{% for row in csv %}
sample {{row.field1}} stuff {{row.field2}} morestuff {{row.field3}}
{% endfor %}
"""
Run Code Online (Sandbox Code Playgroud)

然后输入字典如下

cxt = {'csv': [
    {'field3': 1234, 'field4': 12314},
    {'field3': 2222, 'field4': 1213}
]}
Run Code Online (Sandbox Code Playgroud)

这是我尝试渲染它的方式。

env = Environment(undefined=Undefined)
tmp = env.from_string(tmpstr)
tmpsrc = tmp.render(cxt)
print(tmpsrc)
Run Code Online (Sandbox Code Playgroud)

模板期望变量field1field2field3存在。但是field1field2并且不存在。我的目的是找到所有缺失的变量。

Jinja2默默地忽略丢失的变量。因此,我尝试添加StrictUndefined选项:

errs = []
try:
    env = Environment(undefined=StrictUndefined)
    tmp = env.from_string(tmpstr)
    tmpsrc = tmp.render(cxt)
except Exception as e:
    errs.append(str(e))
print(errs)
Run Code Online (Sandbox Code Playgroud)

但是这次jinja2 抱怨第一个缺少的变量是field1

因此,我尝试了另一种选择DebugUndefined。该选项不会引发异常,并且不会丢失模板输出中缺少的变量占位符。因此,我无法收集丢失的变量。

您能建议我如何在jinja2模板中丢失变量吗?

如果有人想尝试一下,这是可运行的代码:

from jinja2 import BaseLoader,Environment,StrictUndefined,DebugUndefined,Undefined
tmpstr = """
{% for row in csv %}
sample {{row.field1}} stuff {{row.field2}} morestuff {{row.field3}}
{% endfor %}
"""
cxt = {'csv': [
    {'field3': 1234, 'field4': 12314},
    {'field3': 2222, 'field4': 1213}
]}
env = Environment(undefined=Undefined)
tmp = env.from_string(tmpstr)
tmpsrc = tmp.render(cxt)
print('CASE 1: undefined=Undefined')
print(tmpsrc)

errs = []
try:
    env = Environment(undefined=StrictUndefined)
    tmp = env.from_string(tmpstr)
    tmpsrc = tmp.render(cxt)
except Exception as e:
    errs.append(str(e))
print('CASE 2: undefined=StrictUndefined')
print(errs)

errs = []
try:
    env = Environment(undefined=DebugUndefined)
    tmp = env.from_string(tmpstr)
    tmpsrc = tmp.render(cxt)
except Exception as e:
    errs.append(str(e))

print('CASE 3: undefined=DebugUndefined')
print(errs)
print(tmpsrc)
Run Code Online (Sandbox Code Playgroud)

Bal*_*ong 6

我使用找到了解决您问题的方法 jinja2.make_logging_undefined。我和你在同一条船上,一直在寻找答案。大多数答案都指向我使用已解析的模板,但是我无法弄清楚如何将上下文放入已解析的模板中。

我终于可以使用进行这项工作make_logging_undefined。如果要查找所有未定义的变量,请确保仅使用Undefined基类而不是StrictUndefined。使用StrictUndefined将导致Jinja在未定义的第一次遇到时引发异常。

只是免责声明:我不是python也不是jinja专家,因此代码不是最有效或结构化的代码。但这符合我的目的。这只是POC代码。

这是代码:

import jinja2
import logging
from jinja2 import Environment, Undefined
from jinja2.exceptions import UndefinedError

def main():
    templateLoader = jinja2.FileSystemLoader( searchpath="D:\\somelocation\\" )

    logging.basicConfig()
    logger = logging.getLogger('logger')
    LoggingUndefined = jinja2.make_logging_undefined(logger=logger,base=jinja2.Undefined)

    templateEnv = jinja2.Environment( loader=templateLoader, undefined=LoggingUndefined)

    TEMPLATE_FILE = "./example1.jinja"

    template = templateEnv.get_template( TEMPLATE_FILE )

    FAVORITES = [ "chocolates", "lunar eclipses", "rabbits" ]
    # Specify any input variables to the template as a dictionary.
    templateVars = { "title" : "Test Example",
                     "description" : "A simple inquiry of function.",
                     "favorites" : FAVORITES,
                     "whatever" : "1"
                   }    
    # Finally, process the template to produce our final text.
    try:
        outputText = template.render( templateVars )
    except ( UndefinedError) as err:
        print err

if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

example1.jinja:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8" />

  <title>{{ title }}</title>
  <meta name="description" content="{{ description }}" />
</head>

<body>

<div id="content">
  <p>Greetings visitor!  These are a list of my favorite things:</p>

  <ul>
  {% for item in favorites %}
    <li>{{ item }}</li>

  <li>My favorites: {{ favorites[1] }} </li>
  {% endfor %}
  {{ undefined_var1 }}
  {{ underfined_var2 }}
  </ul>
</div>

</body>
</html>
Run Code Online (Sandbox Code Playgroud)

这是示例输出:

WARNING:logger:Template variable warning: undefined_var1 is undefined
WARNING:logger:Template variable warning: underfined_var2 is undefined
Run Code Online (Sandbox Code Playgroud)


Gus*_*rra 5

使用find_undeclared_variableswithDebugUndefined你可以正确地引发一个异常,提到所有丢失的变量:

import jinja2
from jinja2.meta import find_undeclared_variables

env = jinja2.Environment(undefined=jinja2.DebugUndefined)
template = env.from_string('foo={{ foo }}, bar={{ bar}}, baz={{ baz }}')

# Render template without passing all variables
rendered = template.render(foo=1)

# Check if rendering was done correctly
ast = env.parse(rendered)
undefined = find_undeclared_variables(ast)  # {'bar', 'baz'}
if undefined:
    raise jinja2.UndefinedError(f'The following variables are undefined: {undefined!r}')
Run Code Online (Sandbox Code Playgroud)

如果您更喜欢日志记录,您可以使用undefined.

PS:我对 Jinja 比较陌生,但我很惊讶这不是env.render. 我想知道为什么作者/维护者认为默认情况下忽略丢失的变量是一件好事......

  • 如果您在模板中使用字典项并且缺少变量,则解析将失败。这是例子``` import jinja2 from jinja2.meta import find_undeclared_variables env = jinja2.Environment(undefined=jinja2.DebugUndefined) template = env.from_string('foo={{ foo }}, bar={{ bar}}, baz.prop1 ={{ baz.prop1 }} baz.prop2 ={{ baz.prop2 }}') 渲染 = template.render(foo=1,baz={'prop1':'prop1','prop3':' prop2'}) ast = env.parse(rendered) ``` (2认同)