从jinja2调用python函数

问题:从jinja2调用python函数

我正在使用jinja2,并且想使用类似于调用宏的语法来调用python函数作为辅助函数。jinja2似乎旨在阻止我进行函数调用,并坚持要通过将函数复制到模板中作为宏来重复我自己。

有没有简单的方法可以做到这一点?而且,有没有什么方法可以导入整套python函数并使它们从jinja2中进行访问,而无需经历大量的rigamarole(例如编写扩展名)?

I am using jinja2, and I want to call a python function as a helper, using a similar syntax as if I were calling a macro. jinja2 seems intent on preventing me from making a function call, and insists I repeat myself by copying the function into a template as a macro.

Is there any straightforward way to do this? And, is there any way to import a whole set of python functions and have them accessible from jinja2, without going through a whole lot of rigamarole (such as writing an extension)?


回答 0

对于使用Flask的用户,请将其放入您的__init__.py

def clever_function():
    return u'HELLO'

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

然后在您的模板中调用 {{ clever_function() }}

For those using Flask, put this in your __init__.py:

def clever_function():
    return u'HELLO'

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

and in your template call it with {{ clever_function() }}


回答 1

注意:这是Flask特有的!

我知道这篇文章已经很老了,但是在新版本的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) }}

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

另外,您也可以使用Flask中的jinja过滤器。例如使用装饰器:

@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 %}

Note: This is Flask specific!

I know this post is quite old, but there are better methods of doing this in the newer versions of Flask using context processors.

Variables can easily be created:

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

The above can be used in a Jinja2 template with Flask like so:

{{ myexample }}

(Which outputs This is an example)

As well as full fledged functions:

@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)

The above when used like so:

{{ format_price(0.33) }}

(Which outputs the input price with the currency symbol)

Alternatively, you can use jinja filters, baked into Flask. E.g. using decorators:

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

Or, without decorators, and manually registering the function:

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

Filters applied with the above two methods can be used like this:

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

回答 2

我认为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

I think jinja deliberately makes it difficult to run ‘arbitrary’ python within a template. It tries to enforce the opinion that less logic in templates is a good thing.

You can manipulate the global namespace within an Environment instance to add references to your functions. It must be done before you load any templates. For example:

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

回答 3

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的答案

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

You can also give the function in the fields as per Matroskin’s answer

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

Will output:

Hey, my name is Jay Kay

Works with Jinja2 version 2.7.3

And if you want a decorator to ease defining functions on template.globals check out Bruno Bronosky’s answer


回答 4

我喜欢@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__

I like @AJP’s answer. I used it verbatim until I ended up with a lot of functions. Then I switched to a Python function decorator.

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))

Good thing functions have a __name__!


回答 5

从来没有在官方文档或堆栈溢出中看到过如此简单的方法,但是当我发现这一点时,我感到惊讶:

# 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})

Never saw such simple way at official docs or at stack overflow, but i was amazed when found this:

# 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})

回答 6

使用Lambda将模板连接到您的主代码

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

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

{{clever_function(value)}}

Use a lambda to connect the template to your main code

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

Then you can seamlessly call the function in the template

{{clever_function(value)}}

回答 7

要从Jinja2调用python函数,您可以使用自定义过滤器,其工作原理与全局变量类似: http //jinja.pocoo.org/docs/dev/api/#writing-filters

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

{{ data|pythonFct }}

并在python脚本中:

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)

To call a python function from Jinja2, you can use custom filters which work similarly as the globals: http://jinja.pocoo.org/docs/dev/api/#writing-filters

It’s quite simple and useful. In a file myTemplate.txt, I wrote:

{{ data|pythonFct }}

And in a python script:

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)

回答 8

有什么方法可以导入整套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 () }}

is there any way to import a whole set of python functions and have them accessible from jinja2 ?

Yes there is, In addition to the other answers above, this works for me.

Create a class and populate it with the associated methods e.g

class Test_jinja_object:

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

    def clever_function (self):
        return 'hello' 

Then create an instance of your class in your view function and pass the resultant object to your template as a parameter for the render_template function

my_obj = Test_jinja_object()

Now in your template, you can call the class methods in jinja like so

{{ my_obj.clever_function () }}

回答 9

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

app.jinja_env.globals.update(__builtins__)

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

基于John32323的答案

To import all the builtin functions you can use:

app.jinja_env.globals.update(__builtins__)

Add .__dict__ after __builtins__ if this doesn’t work.

Based on John32323’s answer.


回答 10

如果使用Django,则只需将函数与上下文一起传递即可:

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

现在您将能够使用strjinja2模板中的功能

If you are doing it with Django, you can just pass the function with the context:

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

Now you will be able to use the str function in jinja2 template


回答 11

有一个更简单的决定。

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

def y(text):
    return text

然后,在test.html中

{{ y('hi') }}

There’s a much simpler decision.

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

def y(text):
    return text

Then, in test.html:

{{ y('hi') }}