我正在研究基于GAE(python)和JINJA的应用程序。我已经使用from_string
方法从文本字符串创建了JINJA模板。即
template = JINJA.from_string(text)
结果模板如下:
Template(body=[Scope(body=[ScopedEvalContextModifier(options=[Keyword(key='autoescape', value=Name(name='on', ctx='load'))], body=[Output(nodes=[TemplateData(data=u'Dear '), Filter(node=Name(name='customer_name', ctx='load'), name='safe', args=[], kwargs=[], dyn_args=None, dyn_kwargs=None), TemplateData(data=u',\n\n'), Filter(node=Name(name='customer_name_new', ctx='load'), name='extra', args=[], kwargs=[], dyn_args=None, dyn_kwargs=None), TemplateData(data=u'\n \nThank you for choosing '), Name(name='company_name', ctx='load'), TemplateData(data=u'.\n\n')]), If(test=Name(name='start_datetime', ctx='load'), body=[Output(nodes=[TemplateData(data=u'Your '), Name(name='order_type', ctx='load'), TemplateData(data=u' is scheduled for:\n'), Filter(node=Name(name='start_datetime_block', ctx='load'), name='safe', args=[], kwargs=[], dyn_args=None, dyn_kwargs=None), TemplateData(data=u'\nYou can check out the estimated time of arrival for your '), Name(name='order_type', ctx='load'), TemplateData(data=u' using the button below\n'), Filter(node=Name(name='live_link_button', ctx='load'), name='safe', args=[], kwargs=[], dyn_args=None, dyn_kwargs=None), TemplateData(data=u'\n')])], else_=[Output(nodes=[TemplateData(data=u'Your '), Name(name='order_type', ctx='load'), TemplateData(data=u' is now placed.\n')])]), If(test=And(left=Name(name='start_datetime', ctx='load'), right=Name(name='confirmation_required', ctx='load')), body=[Output(nodes=[TemplateData(data=u'Please confirm your availability for this appointment:\n'), Filter(node=Name(name='confirmation_buttons', ctx='load'), name='safe', args=[], kwargs=[], dyn_args=None, dyn_kwargs=None), TemplateData(data=u'\n')])], else_=[]), If(test=Name(name='custom_text', ctx='load'), body=[Output(nodes=[Filter(node=Name(name='custom_text', ctx='load'), name='safe', args=[], kwargs=[], dyn_args=None, dyn_kwargs=None), TemplateData(data=u'\n')])], else_=[]), Output(nodes=[TemplateData(data=u'We look forward to seeing you. In case you have any questions please reach us at '), Name(name='company_email', ctx='load'), TemplateData(data=u'. '), Name(name='company_name', ctx='load'), TemplateData(data=u' '), Name(name='company_address', ctx='load'), TemplateData(data=u' '), Name(name='company_phone', ctx='load')])])])])
现在,我想做的是从该模板中获取所有变量,尤其是我担心此类变量具有某些过滤器,例如上面的模板,预期过滤器为safe
和{{1 }}。请注意,extra
是我的自定义过滤器。
调用extra
方法只会显示关键字列表,但不会显示过滤器。即
meta.find_undeclared_variables
还有什么方法可以同时获得关键字和过滤器名称?
答案 0 :(得分:1)
这是一个可能有用的简单解决方案。它提供了带有过滤器的变量名称(仅包含过滤器的变量):
from jinja2 import Environment, PackageLoader, meta, nodes
def find_filters(ast):
"""Find all the nodes of a given type. If the type is a tuple,
the check is performed for any of the tuple items.
"""
for child in ast.iter_child_nodes():
if isinstance(child, nodes.Filter):
yield child
else:
for result in find_filters(child):
yield result
def filtered_variables(ast):
"""Return variables that have filters, along with their filters. might
return duplicate variable names with different filters
"""
results = []
for i, node in enumerate(find_filters(ast)):
filters = []
f = node
filters.append(f.name)
while isinstance(f.node, nodes.Filter):
f = f.node
filters.append(f.name)
filters.reverse()
results.append((f.node.name, filters))
return results
env = Environment(loader=PackageLoader('templates'))
template = '{% extends "layout.html" %}'\
'{% from "test.html" import a, b as c %}{{ some_variable | a | x}} {{ some_other }}'\
'{% import "meh.html" as meh %}{{ some_variable | b | c | d}}'\
'{% include "muh.html" %}'
ast = env.parse(template)
print(filtered_variables(ast))
输出将是:
[('some_variable', ['a', 'x']), ('some_variable', ['b', 'c', 'd'])]
您可以包括没有过滤器的变量,如下所示:
f_vars = filtered_variables(ast)
filtered = []
for var in f_vars:
filtered.append(var[0])
f = [(x, []) for x in keywords if x not in filtered]
f_vars.extend(f)
print(f_vars)
输出:
[('some_variable', ['a', 'x']), ('some_variable', ['b', 'c', 'd']), ('some_other', [])]
请注意,结果可能有重复的值。这可能会更加有用,因为每次出现变量时都可能会使用不同的过滤器。