我想在jinja2中使用这样的自定义过滤器:
{{ my_list|my_real_map_filter(lambda i: i.something.else)|some_other_filter }}
但是当我实现它时,我收到了这个错误:
TemplateSyntaxError: expected token ',', got 'i'
看来jinja2的语法不允许lambdas作为参数?有一些不错的解决方法吗?现在,我在python中创建lambda然后将其作为变量传递给模板,但我宁愿能够在模板中创建它。
答案 0 :(得分:7)
不,你不能传递一般Python表达式来过滤Jinja2模板
混淆来自于jinja2模板在许多方面与Python语法类似,但您应将其视为具有完全独立语法的代码。
Jinja2有严格的规则,可以预期在模板的哪个部分,它通常不允许python代码,它期望精确类型的表达式,这是非常有限的。
这符合概念,表示和模型应分开,因此模板不允许太多逻辑。无论如何,与许多其他模板选项相比,Jinja2是非常允许的,并且在模板中允许相当多的逻辑。
答案 1 :(得分:6)
我有一个解决方法,我正在排序一个dict对象:
registers = dict(
CMD = dict(
address = 0x00020,
name = 'command register'),
SR = dict(
address = 0x00010,
name = 'status register'),
)
我想循环注册dict,但按地址排序。所以我需要一种方法来按地址排序'领域。为此,我创建了一个自定义过滤器并将lambda表达式作为字符串传递,然后我使用Python的内置eval()来创建真正的lambda:
def my_dictsort(value, by='key', reverse = False):
if by == 'key':
sort_by = lambda x: x[0].lower() # assumes key is a str
elif by == 'value':
sort_by = lambda x: x[1]
else:
sort_by = eval(by) # assumes lambda string, you should error check
return sorted(value, key = sort_by, reverse = reverse)
使用此功能,您可以将其注入jinja2环境,如下所示:
env = jinja2.Environment(...)
env.filters['my_dictsort'] = my_dictsort
env.globals['lookup'] = lookup # queries a database, returns dict
然后从您的模板中调用它:
{% for key, value in lookup('registers') | my_dict_sort("lambda x:x[1]['address']") %}
{{"""\
static const unsigned int ADDR_{key} = 0x0{address:04X}; // {name}
""" | format(key = key, address = value['address'], name = value['name'])
}}
{% endfor %}
输出:
static const unsigned int ADDR_SR = 0x00010; // status register
static const unsigned int ADDR_CMD = 0x00020; // command register
因此,您可以将lambda作为字符串传递,但是您必须添加自定义过滤器才能执行此操作。
答案 2 :(得分:0)
我最近不得不处理相同的问题,我必须在我的list
模板中创建dict
的{{1}},但基本过滤器中没有
这是我的工作习惯:
Ansible
然后我就可以通过这种方式使用它:
({def generate_list_from_list(list, target, var_name="item"):
"""
:param list: the input data
:param target: the applied transformation on each item of the list
:param var_name: the name of the parameter in the lambda, to be able to change it if needed
:return: A list containing for each item the target format
"""
# I didn't put the error handling to keep it short
# Here I evaluate the lambda template, inserting the name of the parameter and the output format
f = eval("lambda {}: {}".format(var_name, target))
return [f(item) for item in list]
# ---- Ansible filters ----
class FilterModule(object):
def filters(self):
return {
'generate_list_from_list': generate_list_from_list
}
是my_input_list
的{{1}},但它可以与list
的任何东西一起使用)
string
或者如果我想重命名lambda参数:
list
这将输出:
# I have to put quotes between the <target> parameter because it evaluates as a string
# The variable is not available at the time of the templating so it would fail otherwise
my_variable: "{{ my_input_list | generate_list_from_list(\"{ 'host': item, 'port': 8000 }\") }}"
中直接调用时:my_variable: "{{ my_input_list | generate_list_from_list(\"{ 'host': variable, 'port': 8000 }\", var_name="variable") }}"
Python
希望这对某人有帮助