从 jinja2调用 python 函数

我正在使用 jinja2,并且我想要调用一个 python 函数作为助手,使用类似于调用宏的语法。Jinja2似乎有意阻止我进行函数调用,并坚持让我将函数作为宏复制到模板中来重复自己的操作。

有什么直接的方法吗?而且,有没有办法导入一整套 python 函数,并让它们可以从 jinja2访问,而不必经历一大堆冗长的程序(比如编写扩展) ?

189444 次浏览

我认为 jinja 故意使在模板中运行“任意”python 变得困难。它试图强制执行这样一种观点,即模板中逻辑较少是一件好事。

可以在 Environment实例中操作全局命名空间,以添加对函数的引用。它必须做 之前你加载任何模板。例如:

from jinja2 import Environment, FileSystemLoader


def clever_function(a, b):
return u''.join([b, a])


env = Environment(loader=FileSystemLoader('/path/to/templates'))
env.globals['clever_function'] = clever_function

对于那些使用烧瓶的人,把这个放在你的 __init__.py:

def clever_function():
return u'HELLO'


app.jinja_env.globals.update(clever_function=clever_function)

并在您的模板调用它与 \{\{ clever_function() }}

注意: 这是烧瓶专用的!

我知道这篇文章很老了,但是在 Flask 的新版本中使用上下文处理器有更好的方法来实现这一点。

可以很容易地创建变量:

@app.context_processor
def example():
return dict(myexample='This is an example')

以上内容可以在带有 Flask 的 Jinja2模板中使用,如下所示:

\{\{ myexample }}

(输出 This is an example)

以及全面的职能:

@app.context_processor
def utility_processor():
def format_price(amount, currency=u'€'):
return u'{0:.2f}{1}'.format(amount, currency)
return dict(format_price=format_price)

以上内容在这样使用时:

\{\{ format_price(0.33) }}

(输出带有货币符号的输入价格)

或者,你也可以使用 忍者过滤器,将它嵌入到烧瓶中。例如,使用装饰器:

@app.template_filter('reverse')
def reverse_filter(s):
return s[::-1]

或者,不用装饰器,手动注册函数:

def reverse_filter(s):
return s[::-1]
app.jinja_env.filters['reverse'] = reverse_filter

以上两种方法应用的过滤器可以这样使用:

{% for x in mylist | reverse %}
{% endfor %}

使用 lambda 将模板连接到主代码

return render_template("clever_template", clever_function=lambda x: clever_function x)

然后您可以无缝地调用模板中的函数

\{\{clever_function(value)}}
from jinja2 import Template


def custom_function(a):
return a.replace('o', 'ay')


template = Template('Hey, my name is \{\{ custom_function(first_name) }} \{\{ func2(last_name) }}')
template.globals['custom_function'] = custom_function

还可以按照 Matroskin 的回答在字段中给出函数

fields = {'first_name': 'Jo', 'last_name': 'Ko', 'func2': custom_function}
print template.render(**fields)

将输出:

Hey, my name is Jay Kay

使用 Jinja2版本2.7.3

如果你想要一个修饰器来简化 template.globals上的定义函数,请查看 Bruno Bronosky 的回答

要从 Jinja2调用 python 函数,可以使用与 globals类似的 定制过滤器

非常简单有用。 在一个文件 myTemplate.txt 中,我写道:

\{\{ data | pythonFct }}

在一个巨蟒脚本里:

import jinja2


def pythonFct(data):
return "This is my data: {0}".format(data)
    

input="my custom filter works!"
  

loader = jinja2.FileSystemLoader(path or './')
env = jinja2.Environment(loader=loader)
env.filters['pythonFct'] = pythonFct
result = env.get_template("myTemplate.txt").render(data=input)
print(result)

如果你使用 Django,你可以只传递函数的上下文:

context = {
'title':'My title',
'str': str,
}
...
return render(request, 'index.html', context)

现在您将能够在 jinja2模板中使用 str函数

从来没有在官方文件或堆栈溢出中看到过这么简单的方法,但当我发现这个时,我感到惊讶:

# jinja2.__version__ == 2.8
from jinja2 import Template


def calcName(n, i):
return ' '.join([n] * i)


template = Template("Hello \{\{ calcName('Gandalf', 2) }}")


template.render(calcName=calcName)
# or
template.render({'calcName': calcName})

有没有办法导入一整套 python 函数并让它们可以从 jinja2访问?

是的,除了上面的其他答案,这对我很有用。

创建一个类并用相关的方法填充它,例如

class Test_jinja_object:


def __init__(self):
self.myvar = 'sample_var'


def clever_function (self):
return 'hello'

然后在视图函数中创建类的实例,并将结果对象作为 render _ template 函数的参数传递给模板

my_obj = Test_jinja_object()

现在在您的模板中,您可以像这样调用 jinja 中的类方法

\{\{ my_obj.clever_function () }}

我喜欢 @ AJP 的回答。我一字不差地使用它,直到得到许多函数为止。然后我换成了 Python 函数修饰器

from jinja2 import Template


template = '''
Hi, my name is \{\{ custom_function1(first_name) }}
My name is \{\{ custom_function2(first_name) }}
My name is \{\{ custom_function3(first_name) }}
'''
jinga_html_template = Template(template)


def template_function(func):
jinga_html_template.globals[func.__name__] = func
return func


@template_function
def custom_function1(a):
return a.replace('o', 'ay')


@template_function
def custom_function2(a):
return a.replace('o', 'ill')


@template_function
def custom_function3(a):
return 'Slim Shady'


fields = {'first_name': 'Jo'}
print(jinga_html_template.render(**fields))

好东西功能有 __name__

要导入所有可以使用的内置函数:

app.jinja_env.globals.update(__builtins__)

如果这不起作用,在 __builtins__之后添加 .__dict__

基于 约翰32323的回答

有个更简单的决定。

@app.route('/x')
def x():
return render_template('test.html', foo=y)


def y(text):
return text

然后,在 Test.html中:

\{\{ foo('hi') }}

@ John32323的答案是一个非常干净的解决方案。

这里是相同的一个,但保存到一个单独的文件,也许更干净。

创建帮助文件

App helper.py

from app import app


def clever_function_1():
return u'HELLO'


def clever_function_2(a, b):
return a + b






app.jinja_env.globals.update(
clever_function_1=clever_function_1,
clever_function_2=clever_function_2,
)

从应用程序导入

App py

from app import routes
from app import helper   # add this one

像这样使用

应用程序模板 some.html


\{\{ clever_function_1() }}
\{\{ clever_function_2(a, b) }}


对于那些使用 FastApi 的人,把这个放在你的 __init__.py中:

from fastapi.templating import Jinja2Templates
templates = Jinja2Templates(directory="templates")


def clever_function():
return u'HELLO'


templates.env.globals.update(clever_function=clever_function)

并在您的模板调用它与 \{\{ clever_function() }}

Creating a global function without passing to the template


@app.template_global('double')
def double(n):
return 2 * n


Jinja Usage`enter code here`


\{\{double(77)}}


Or
Creating a filter in jinja.




@app.template_filter('geo_stuff')
def hellome(a,b='dadadd'):
d=a+'it is jerry'
return d
jinja use
\{\{'foo'|geo_stuff}}