Как получить переменные вместе с именем их фильтра из шаблона JINJA2 - PullRequest
2 голосов
/ 21 марта 2019

Я работаю над приложением GAE (python) и JINJA.Я создал шаблон JINJA из текстовой строки, используя метод from_string.то есть

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 и extra.Обратите внимание, что extra - мой пользовательский фильтр.

Вызов метода meta.find_undeclared_variables дает только список ключевых слов, но не их фильтры.т.е.

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

Можно ли как-нибудь найти ключевые слова вместе с именами фильтров?

1 Ответ

1 голос
/ 23 марта 2019

Вот простое решение, которое может помочь.Он дает имя переменной с фильтрами (только переменные, которые имеют фильтры):

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', [])]

Обратите внимание, что результат может иметь повторяющиеся значения.Это может быть более полезным, так как разные фильтры могут присутствовать при каждом появлении переменной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...