jinja2からPython関数を呼び出す


144

私はjinja2を使用しており、マクロを呼び出す場合と同様の構文を使用して、ヘルパーとしてpython関数を呼び出します。jinja2は私が関数を呼び出せないようにすることを目的としており、関数をマクロとしてテンプレートにコピーすることで繰り返します。

これを行う簡単な方法はありますか?そして、Python関数のセット全体をインポートして、jinja2からアクセスできるようにする方法はありますか?

回答:


223

Flaskを使用している場合は、これを次の場所に配置します__init__.py

def clever_function():
    return u'HELLO'

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

テンプレートでそれを呼び出します {{ clever_function() }}


このような複数の関数を渡すことができますか?
ffghfgh 2017

6
新しいバージョン(私はJinja2 2.9.6を使用しています)では、はるかに簡単に動作するようです。あなたは、変数を使用するのと同じように(より複雑な状況でも動作します)機能を使用しますfrom jinja2 import Template ##newline## def clever_function(): ##newline## return "Hello" ##newline## template = Template("{{ clever_function() }}") ##newline## print(template.render(clever_function=clever_function))
SemjonMössinger

1
8年後でも、Flaskを使用している場合、これは最近のどの回答よりもクリーンなソリューションのようです。@ffghfghからの古い質問に答えるには、はい—複数の関数を渡すことができます。
kevinmicke

132

注:これは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に焼き付けたジンジャフィルターを使用できます。たとえば、デコレータを使用します。

@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

上記の2つの方法で適用されたフィルターは、次のように使用できます。

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

4
これらの関数はどこに存在する必要がありますか、初期化、ビュー、またはどこにでもありますか?
knk 2014年

3
__init__.pyあなたがflask.Flask(__name__)そこで宣言したと仮定します。
リアムスタンレー

6
Jinja2について質問された質問に反対票を投じ、回答はFlask固有です。
AJP 2014年

13
@AJPそれでも理論的には質問に答えます。これは問題を解決する1つの方法ですが、Flaskも使用しています。JavaScriptのすべての質問がjQueryの有無にかかわらず代替案を提供することや、Pythonに関する質問がPython2と3の両方に回答することがよくあります。この質問は、Flaskを除外するものではありませんでした。(Py2に関する質問とは異なり、Py3の回答は除外されます)。この答えは私を助けました。
jeromej

2
非常に役に立ち、まさに私が探していたものです。Jinja2はWebフレームワークの一部であるため、バックエンドから完全に独立しているわけではありません。私はDjangoとFlaskの両方でPythonとこの投稿を使用して作業しています。質問を過度に指定しようとすることは、不必要に曖昧であるのと同じくらい私にとって有害で​​す。

76

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

5
私もこれを発見しました-次のようなものを使用してモジュールを追加できます: import utils.helpers env.globals['helpers'] = utils.helpers
Lee

@リー。はい、名前空間(モジュール)、関数、クラスインスタンスなどを「挿入」できます。これは便利ですが、makoなどの他のテンプレートエンジンほど柔軟ではありません。それでも、ジンジャには他にも良い点があります。それが役に立ったならば、あなたが答えを受け入れるならば、私は感謝します:)
Rob Cowie '19年

私のApp Engineプロジェクト(webapp2とjinja2)をやっているときに私のためにトリックをしました。感謝
Sojan V Jose

@RobCowie clever_functionを辞書env.globalsに追加した後、テンプレートから関数を呼び出すにはどうすればよいですか。
ホルヘヴィディーニャ

1
したがって、 {{ clever_function('a', 'b') }}
Rob Cowie

41
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で動作します

そして、デコレータで関数の定義を簡単にしたい場合は、Bruno Bronoskyの答えをtemplate.globalsチェックしてください


8
おそらく、他の全員の回答に反対票を投じたためでしょう:(
Borko Kovacev

13
@BorkoKovacevそれは正当な理由ではありません。私は2つの回答のみに反対票を投じました。Jinja2ではなくFlaskに関する回答。彼らがトピックやJinja2について回答を編集したい場合は、賛成票を投じます。
AJP、2015年

Tx @BorkoKovacev :)
AJP

1
この回答の関数デコレータバージョンを作成しました。現在0票で最下位にあります:、-(stackoverflow.com/a/47291097/117471
Bruno Bronosky 2017年

2
@BrunoBronoskyいいね。投票した:) ...さらに10年間与えると、私のものよりも高くなる可能性があります:P ...ただし、フラスコをキャッチすることはありません; P
AJP

25

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


1
これはめちゃくちゃかっこいいです。Pythonで関数に注釈を付けると、関数名が注釈の関数に自動的に渡されますか?
Mutant_city

@mutant_city、うん。Python関数デコレーターのリンクを読んでください。素晴らしいもの!
ブルーノブロノスキー

1
@BrunoBronosky Pythonデコレータの賢明でクリーンな使用の優れたデモンストレーション。素晴らしいポスト!
dreftymac

1
なんて素晴らしい実装でしょう!
フィリップオジェ

16

公式ドキュメントやスタックオーバーフローでそのような単純な方法を見たことはありませんが、これを見つけて驚いた:

# 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のファーストクラス
シチズン

8

ラムダを使用してテンプレートをメインコードに接続する

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

次に、テンプレートで関数をシームレスに呼び出すことができます

{{clever_function(value)}}

1
ラムダ関数の賢い使い方。

23
@odiumediae:いいえ、そうではありません。それは完全に不要です。関数ハンドル自体を渡すだけです:clever_function = clever_function
vezult

@vezultなるほど。どうすればそれを逃すことができますか?それを片付けてくれてありがとう!

6

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)

5

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

同等で少し簡単な方法:テンプレートのすべての関数をモジュールに入れ、そのモジュールをインポートして、テンプレートグローバルとして追加します。モジュールは機能:)含むオブジェクトです(ただし、方法を! -自己のparamが不要とreqiuredなしクラス)
エリックアラウージョ

@ÉricAraujoすべてのテンプレートではなく、1つまたは2つのテンプレートの関数セットのみが必要な場合 また、異なるjinjasテンプレートに異なるPython関数のセットが必要な場合はどうなりますか?それらをすべてクラスのメソッドとして配置するのではなく、テンプレートグローバルとしてインポートし、必要なメソッドのみをクラスに渡すことは、依然として効果的だと思いますか?
Kudehinbu Oluwaponle

特定のテンプレートでのみ使用するには、これらのテンプレートを使用するビューによって返されるテンプレートコンテキスト辞書にのみ、関数(または関数を含むモジュール)を追加します。
エリックアラウージョ

3

使用できるすべての組み込み関数をインポートするには:

app.jinja_env.globals.update(__builtins__)

これが機能しない場合は、.__dict__後で追加し__builtins__ます。

John32323の回答に基づく。


2

Djangoで実行している場合は、次のコンテキストで関数を渡すだけです。

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

これstrで、jinja2テンプレートで関数を使用できるようになります


1

はるかに簡単な決定があります。

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

def y(text):
    return text

次に、test.htmlで

{{ y('hi') }}

jinja2.exceptions.UndefinedError:「y」は未定義
lww

はい、cuzはtest.htmlでfooを使用することになっています
luckyguy73
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.