【问题标题】:How to get variables along with their filter name from JINJA2 template如何从 JINJA2 模板中获取变量及其过滤器名称
【发布时间】:2019-03-21 07:14:55
【问题描述】:

我正在开发基于 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')])])])])

现在,我想做的是我想从这个模板中获取所有变量,特别是我关心这些变量,它们有一些过滤器,比如上面的模板预期过滤器是safeextra。请注意,extra 是我的自定义过滤器。

调用meta.find_undeclared_variables 方法只会给我关键字列表,而不是它们的过滤器。即

parsed_content = JINJA.parse(text)
keywords = meta.find_undeclared_variables(parsed_content)

有什么方法可以同时获取关键字和过滤器名称?

【问题讨论】:

    标签: python django flask jinja2


    【解决方案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', [])]
    

    请注意,结果可能有重复值。这可能更有用,因为每次出现的变量都可能存在不同的过滤器。

    【讨论】:

    • 非常感谢!正是我想要的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多