拡張機能—Jinjaドキュメント
拡張機能
Jinjaは、フィルター、テスト、グローバルを追加したり、パーサーを拡張したりできる拡張機能をサポートしています。 拡張機能の主な動機は、国際化のサポートを追加するなど、頻繁に使用されるコードを再利用可能なクラスに移動することです。
拡張機能の追加
拡張機能は、作成時にJinja環境に追加されます。 拡張機能を追加するには、拡張機能クラスのリストまたはインポートパスを Environment コンストラクターのextensions
パラメーターに渡します。 次の例では、i18n拡張機能がロードされたJinja環境を作成します。
jinja_env = Environment(extensions=['jinja2.ext.i18n'])
作成後に拡張機能を追加するには、 add_extension()メソッドを使用します。
jinja_env.add_extension('jinja2.ext.debug')
i18n拡張
インポート名: jinja2.ext.i18n
i18n拡張機能は、 gettext または Babel と組み合わせて使用できます。 有効にすると、Jinjaはブロックを翻訳可能としてマークするtrans
ステートメントを提供し、gettext
を呼び出します。
有効にした後、アプリケーションはgettext
、ngettext
、およびオプションでpgettext
とnpgettext
の機能をグローバルに、またはレンダリング時に提供する必要があります。 _()
関数がgettext
関数のエイリアスとして追加されました。
環境メソッド
拡張機能を有効にした後、環境は次の追加のメソッドを提供します。
- jinja2.Environment.install_gettext_translations(translations, newstyle=False)
環境の翻訳をグローバルにインストールします。
translations
オブジェクトは、gettext
、ngettext
、およびオプションでpgettext
とnpgettext
を実装する必要があります。gettext.NullTranslations
、gettext.GNUTranslations
、および Babel のTranslations
がサポートされています。バージョン3.0で変更:
pgettext
およびnpgettext
を追加。バージョン2.5で変更:新しいスタイルのgettextサポートが追加されました。
- jinja2.Environment.install_null_translations(newstyle=False)
no-opgettext関数をインストールします。 これは、アプリケーションを国際化に向けて準備したいが、まだ完全なシステムを実装したくない場合に役立ちます。
バージョン2.5で変更:新しいスタイルのgettextサポートが追加されました。
- jinja2.Environment.install_gettext_callables(gettext, ngettext, newstyle=False, pgettext=None, npgettext=None)
指定された
gettext
、ngettext
、pgettext
、およびnpgettext
呼び出し可能オブジェクトを環境にインストールします。 これらは、gettext.gettext()
、gettext.ngettext()
、gettext.pgettext()
、およびgettext.npgettext()
とまったく同じように動作する必要があります。newstyle
がアクティブになっている場合、呼び出し可能オブジェクトは、新しいスタイルの呼び出し可能オブジェクトのように機能するようにラップされます。 詳細については、 New Style Gettext を参照してください。バージョン3.0で変更:
pgettext
およびnpgettext
を追加。バージョン2.5の新機能:新しいスタイルのgettextサポートが追加されました。
- jinja2.Environment.uninstall_gettext_translations()
- 環境のグローバルにインストールされた翻訳をアンインストールします。
- jinja2.Environment.extract_translations(source)
指定されたテンプレートノードまたはソースからローカライズ可能な文字列を抽出します。
見つかったすべての文字列に対して、この関数は
(lineno, function, message)
タプルを生成します。ここで、lineno
は、文字列が見つかった行の番号です。function
は、使用されるgettext
関数の名前です(文字列が埋め込みPythonコードから抽出された場合)。message
は文字列自体、または複数の引数を持つ関数の文字列のタプルです。
複数の言語で利用できるが、すべてのユーザーに同じ言語を提供するWebアプリケーション(たとえば、フランス語のコミュニティ用にインストールされた多言語フォーラムソフトウェア)の場合、環境の作成時に翻訳がインストールされることがあります。
translations = get_gettext_translations()
env = Environment(extensions=["jinja2.ext.i18n"])
env.install_gettext_translations(translations)
get_gettext_translations
関数は、たとえばgettext.find
を使用して、現在の構成のトランスレーターを返します。
テンプレート設計者向けのi18n
拡張機能の使用法については、テンプレートドキュメントで説明されています。
空白のトリミング
バージョン2.10の新機能。
{% trans %}
ブロック内では、テキストのブロックが翻訳ファイル内に単一のスペースがある単純な文字列のように見えるように、改行と空白をトリミングすると便利な場合があります。
ext.i18n.trimmed
ポリシーを有効にすると、改行と周囲の空白を自動的にトリミングできます。
新しいスタイルのGettext
バージョン2.5の新機能。
新しいスタイルのgettext呼び出しは、入力が少なく、エラーが発生しにくく、自動エスケープをより適切にサポートします。
env.newstyle_gettext = True
を設定するか、newstyle=True
をenv.install_translations
に渡すことで、「新しいスタイル」のgettext呼び出しを使用できます。 これらはBabel抽出ツールで完全にサポートされていますが、他の抽出ツールでは期待どおりに機能しない可能性があります。
標準のgettext
呼び出しでは、文字列のフォーマットは|format
フィルターで行われる別のステップです。 これには、ngettext
呼び出しの複製作業が必要です。
{{ gettext("Hello, World!") }}
{{ gettext("Hello, %(name)s!")|format(name=name) }}
{{ ngettext(
"%(num)d apple", "%(num)d apples", apples|count
)|format(num=apples|count) }}
{{ pgettext("greeting", "Hello, World!") }}
{{ npgettext(
"fruit", "%(num)d apple", "%(num)d apples", apples|count
)|format(num=apples|count) }}
新しいスタイルgettext
により、フォーマットが通話の一部になり、舞台裏で一貫性が強化されます。
{{ gettext("Hello, World!") }}
{{ gettext("Hello, %(name)s!", name=name) }}
{{ ngettext("%(num)d apple", "%(num)d apples", apples|count) }}
{{ pgettext("greeting", "Hello, World!") }}
{{ npgettext("fruit", "%(num)d apple", "%(num)d apples", apples|count) }}
newstylegettextの利点は次のとおりです。
- 個別のフォーマット手順はありません。
|format
フィルターを使用することを覚えておく必要はありません。 - 名前付きプレースホルダーのみが許可されます。 これにより、位置プレースホルダーは意味のある位置を切り替えることができないため、翻訳者が直面する一般的な問題が解決されます。 名前付きプレースホルダーは、常に、どの値がどこに行くかについてのセマンティック情報を伝達します。
- プレースホルダーが使用されていない場合でも文字列フォーマットが使用されるため、すべての文字列で一貫したフォーマットが使用されます。
100%%
など、生のパーセント記号は%%
としてエスケープすることを忘れないでください。 - 翻訳された文字列は安全とマークされ、フォーマットは必要に応じてエスケープを実行します。 パラメータがすでにエスケープされている場合は、パラメータを
|safe
としてマークします。
式ステートメント
インポート名: jinja2.ext.do
「do」別名式ステートメント拡張は、変数式のように機能するが戻り値を無視する単純なdo
タグをテンプレートエンジンに追加します。
ループ制御
インポート名: jinja2.ext.loopcontrols
この拡張機能は、ループ内のbreak
およびcontinue
のサポートを追加します。 有効にした後、JinjaはPythonとまったく同じように機能する2つのキーワードを提供します。
ステートメント付き
インポート名: jinja2.ext.with_
バージョン2.9で変更:この拡張機能は組み込みになり、何も実行されなくなりました。
自動エスケープ拡張
インポート名: jinja2.ext.autoescape
バージョン2.9で変更:この拡張機能は削除され、組み込みになりました。 拡張機能を有効にしても、何も実行されなくなりました。
デバッグ拡張機能
インポート名: jinja2.ext.debug
{% debug %}
タグを追加して、現在のコンテキストと使用可能なフィルターおよびテストをダンプします。 これは、デバッガーを設定せずにテンプレートで使用できるものを確認するのに役立ちます。
拡張機能の記述
拡張機能を作成することで、Jinjaにカスタムタグを追加できます。 これは簡単な作業ではなく、デフォルトのタグと式がすべての一般的なユースケースをカバーしているため、通常は必要ありません。 i18n拡張機能は、拡張機能が役立つ理由の良い例です。 もう1つは、フラグメントキャッシングです。
拡張機能を作成するときは、渡されるノードツリーを検証しないJinjaテンプレートコンパイラを使用していることに注意する必要があります。 ASTの形式が正しくないと、デバッグがひどいあらゆる種類のコンパイラエラーまたはランタイムエラーが発生します。 作成したノードを正しく使用していることを常に確認してください。 以下のAPIドキュメントは、存在するノードとその使用方法を示しています。
拡張機能の例
キャッシュ
次の例では、 cachelib ライブラリを使用して、Jinjaのcache
タグを実装しています。
from jinja2 import nodes
from jinja2.ext import Extension
class FragmentCacheExtension(Extension):
# a set of names that trigger the extension.
tags = {"cache"}
def __init__(self, environment):
super().__init__(environment)
# add the defaults to the environment
environment.extend(fragment_cache_prefix="", fragment_cache=None)
def parse(self, parser):
# the first token is the token that started the tag. In our case
# we only listen to ``'cache'`` so this will be a name token with
# `cache` as value. We get the line number so that we can give
# that line number to the nodes we create by hand.
lineno = next(parser.stream).lineno
# now we parse a single expression that is used as cache key.
args = [parser.parse_expression()]
# if there is a comma, the user provided a timeout. If not use
# None as second parameter.
if parser.stream.skip_if("comma"):
args.append(parser.parse_expression())
else:
args.append(nodes.Const(None))
# now we parse the body of the cache block up to `endcache` and
# drop the needle (which would always be `endcache` in that case)
body = parser.parse_statements(["name:endcache"], drop_needle=True)
# now return a `CallBlock` node that calls our _cache_support
# helper method on this extension.
return nodes.CallBlock(
self.call_method("_cache_support", args), [], [], body
).set_lineno(lineno)
def _cache_support(self, name, timeout, caller):
"""Helper callback."""
key = self.environment.fragment_cache_prefix + name
# try to load the block from the cache
# if there is no fragment in the cache, render it and store
# it in the cache.
rv = self.environment.fragment_cache.get(key)
if rv is not None:
return rv
rv = caller()
self.environment.fragment_cache.add(key, rv, timeout)
return rv
そして、これが環境でそれをどのように使用するかです:
from jinja2 import Environment
from cachelib import SimpleCache
env = Environment(extensions=[FragmentCacheExtension])
env.fragment_cache = SimpleCache()
テンプレート内で、ブロックをキャッシュ可能としてマークすることができます。 次の例では、サイドバーを300秒間キャッシュします。
{% cache 'sidebar', 300 %}
<div class="sidebar">
...
</div>
{% endcache %}
インラインgettext
次の例は、 Extension.filter_stream()を使用して、Jinjaブロックを必要とせずに、静的データとインラインで_()
gettext関数への呼び出しを解析する方法を示しています。
<h1>_(Welcome)</h1>
<p>_(This is a paragraph)</p>
i18n拡張機能をロードして設定する必要があります。
import re
from jinja2.exceptions import TemplateSyntaxError
from jinja2.ext import Extension
from jinja2.lexer import count_newlines
from jinja2.lexer import Token
_outside_re = re.compile(r"\\?(gettext|_)\(")
_inside_re = re.compile(r"\\?[()]")
class InlineGettext(Extension):
"""This extension implements support for inline gettext blocks::
<h1>_(Welcome)</h1>
<p>_(This is a paragraph)</p>
Requires the i18n extension to be loaded and configured.
"""
def filter_stream(self, stream):
paren_stack = 0
for token in stream:
if token.type != "data":
yield token
continue
pos = 0
lineno = token.lineno
while True:
if not paren_stack:
match = _outside_re.search(token.value, pos)
else:
match = _inside_re.search(token.value, pos)
if match is None:
break
new_pos = match.start()
if new_pos > pos:
preval = token.value[pos:new_pos]
yield Token(lineno, "data", preval)
lineno += count_newlines(preval)
gtok = match.group()
if gtok[0] == "\\":
yield Token(lineno, "data", gtok[1:])
elif not paren_stack:
yield Token(lineno, "block_begin", None)
yield Token(lineno, "name", "trans")
yield Token(lineno, "block_end", None)
paren_stack = 1
else:
if gtok == "(" or paren_stack > 1:
yield Token(lineno, "data", gtok)
paren_stack += -1 if gtok == ")" else 1
if not paren_stack:
yield Token(lineno, "block_begin", None)
yield Token(lineno, "name", "endtrans")
yield Token(lineno, "block_end", None)
pos = match.end()
if pos < len(token.value):
yield Token(lineno, "data", token.value[pos:])
if paren_stack:
raise TemplateSyntaxError(
"unclosed gettext expression",
token.lineno,
stream.name,
stream.filename,
)
拡張API
拡大
拡張機能は常に jinja2.ext.Extension クラスを拡張する必要があります。
- class jinja2.ext.Extension(environment)
拡張機能を使用して、パーサーレベルでJinjaテンプレートシステムに機能を追加できます。 カスタム拡張機能は環境にバインドされていますが、 self に環境固有のデータを保存しない場合があります。 これは、コピーを作成して environment 属性を再割り当てすることにより、拡張機能を別の環境(オーバーレイ用)にバインドできるためです。
拡張機能は環境によって作成されるため、構成の引数を受け入れることはできません。 ファクトリ関数を使用してこれを回避したい場合がありますが、拡張機能はインポート名で識別されるため、それは不可能です。 拡張機能を構成する正しい方法は、構成値を環境に保存することです。 このようにすると、環境が中央構成ストレージとして機能するようになるため、属性が衝突する可能性があります。そのため、拡張機能では、構成に選択する名前が一般的すぎないようにする必要があります。 たとえば、
prefix
はひどい名前ですが、fragment_cache_prefix
は、拡張機能(フラグメントキャッシュ)の名前を含む適切な名前です。- パラメーター
- リターンタイプ
なし
- identifier
拡張子の識別子。 これは常に拡張クラスの真のインポート名であり、変更しないでください。
- tags
拡張機能がカスタムタグを実装している場合、これは拡張機能がリッスンしているタグ名のセットです。
- attr(name, lineno=None)
現在の拡張機能の属性ノードを返します。 これは、生成されたテンプレートコードの拡張機能に定数を渡すのに役立ちます。
self.attr('_my_attribute', lineno=lineno)
- パラメーター
名前( str )–
lineno (オプション [ int ] )–
- リターンタイプ
jinja2.nodes.ExtensionAttribute
- call_method(name, args=None, kwargs=None, dyn_args=None, dyn_kwargs=None, lineno=None)
拡張機能のメソッドを呼び出します。 これは、 attr() +
jinja2.nodes.Call
のショートカットです。- パラメーター
名前( str )–
args (オプション [ リスト [ jinja2.nodes.Expr ] ] )–
kwargs (オプション [ リスト [ jinja2.nodes.Keyword ] ] )–
dyn_args (オプション [ jinja2.nodes.Expr ] )–
dyn_kwargs (オプション [ jinja2.nodes.Expr ] )–
lineno (オプション [ int ] )–
- リターンタイプ
jinja2.nodes.Call
- filter_stream(stream)
返されたトークンをフィルタリングするために使用できる TokenStream が渡されます。 このメソッドは、反復可能な Token を返す必要がありますが、 TokenStream を返す必要はありません。
- パラメーター
ストリーム(トークンストリーム)–
- リターンタイプ
Union [ TokenStream 、Iterable [ Token ]]
- parse(parser)
タグのいずれかが一致した場合、このメソッドはパーサーを最初の引数として呼び出されます。 パーサーストリームが指しているトークンは、一致した名前トークンです。 このメソッドは、1つまたは複数のノードのリストを返す必要があります。
- パラメーター
パーサー(パーサー)–
- リターンタイプ
Union [jinja2.nodes.Node、List [jinja2.nodes.Node]]
- preprocess(source, name, filename=None)
このメソッドは、実際の字句解析の前に呼び出され、ソースを前処理するために使用できます。 ファイル名はオプションです。 戻り値は前処理されたソースである必要があります。
- パラメーター
ソース( str )–
名前(オプション [ str ] )–
ファイル名(オプション [ str ] )–
- リターンタイプ
str
パーサー
Extension.parse()に渡されるパーサーは、さまざまなタイプの式を解析する方法を提供します。 次の方法は、拡張機能で使用できます。
- class jinja2.parser.Parser(environment, source, name=None, filename=None, state=None)
これは、Jinjaが使用する中心的な構文解析クラスです。 拡張機能に渡され、式またはステートメントの解析に使用できます。
- パラメーター
環境(環境)–
ソース( str )–
名前(オプション [ str ] )–
ファイル名(オプション [ str ] )–
状態(オプション [ str ] )–
- リターンタイプ
なし
- filename
パーサーが処理するテンプレートのファイル名。 これは、テンプレートのロード名ではなくです。 ロード名については、 name を参照してください。 ファイルシステムからロードされなかったテンプレートの場合、これは
None
です。
- name
テンプレートのロード名。
- stream
現在の TokenStream
- fail(msg, lineno=None, exc=<class 'jinja2.exceptions.TemplateSyntaxError'>)
メッセージ、渡された行番号または最後の行番号、および現在の名前とファイル名で exc を発生させる便利なメソッド。
- パラメーター
msg ( str )–
lineno (オプション [ int ] )–
exc ( Type [ jinja2.exceptions.TemplateSyntaxError ] )–
- リターンタイプ
te.NoReturn
- free_identifier(lineno=None)
新しい空き識別子を[X32X] として返します。
- パラメーター
lineno (オプション [ int ] )–
- リターンタイプ
jinja2.nodes.InternalName
- parse_assign_target(with_tuple=True, name_only=False, extra_end_rules=None, with_namespace=False)
割り当てターゲットを解析します。 Jinjaはタプルへの割り当てを許可するため、この関数は許可されたすべての割り当てターゲットを解析できます。 タプルへのデフォルトの割り当ては解析されますが、 with_tuple を False に設定することで無効にできます。 名前への割り当てのみが必要な場合は、 name_only を True に設定できます。 extra_end_rules パラメーターは、タプル解析関数に転送されます。 with_namespace が有効になっている場合、名前空間の割り当てが解析される可能性があります。
- パラメーター
with_tuple ( bool )–
name_only ( bool )–
extra_end_rules (オプション [ タプル [ str 、 ... ] ] )–
with_namespace ( bool )–
- リターンタイプ
Union [jinja2.nodes.NSRef、jinja2.nodes.Name、jinja2.nodes.Tuple]
- parse_expression(with_condexpr=True)
式を解析します。 オプションの with_condexpr パラメーターが False に設定されている場合、デフォルトではすべての式が解析されます。条件式は解析されません。
- パラメーター
with_condexpr ( bool )–
- リターンタイプ
jinja2.nodes.Expr
- parse_statements(end_tokens, drop_needle=False)
終了トークンの1つに到達するまで、複数のステートメントをリストに解析します。 これは、必要に応じてテンプレートデータも解析するため、ステートメントの本体を解析するために使用されます。 パーサーは、現在のトークンがコロンであるかどうかを最初にチェックし、コロンがある場合はスキップします。 次に、ブロックの終わりをチェックし、 end_tokens のいずれかに到達するまで解析します。 デフォルトでは、呼び出しの終了時にストリーム内のアクティブなトークンは、一致した終了トークンです。 これが不要な場合は、 drop_needle を True に設定して、終了トークンを削除できます。
- パラメーター
end_tokens (タプル [ str 、 ... ] [ X85X])– –
drop_needle ( bool )–
- リターンタイプ
リスト[jinja2.nodes.Node]
- parse_tuple(simplified=False, with_condexpr=True, extra_end_rules=None, explicit_parentheses=False)
parse_expression と同様に機能しますが、複数の式がコンマで区切られている場合、
Tuple
ノードが作成されます。 このメソッドは、コンマが見つからない場合、タプルの代わりに正規表現を返すこともできます。デフォルトの解析モードはフルタプルです。 simpled が True の場合、名前とリテラルのみが解析されます。 no_condexpr パラメーターは parse_expression()に転送されます。
タプルは区切り文字を必要とせず、偽のコンマで終わる可能性があるため、タプルの終わりを示す追加のヒントが必要です。 たとえば、forループは、 for と in の間のタプルをサポートします。 その場合、 extra_end_rules は
['name:in']
に設定されます。explicit_parentheses は、解析が括弧内の式によってトリガーされた場合にtrueになります。 これは、空のタプルが有効な式であるかどうかを判断するために使用されます。
- パラメーター
簡略化( bool )–
with_condexpr ( bool )–
extra_end_rules (オプション [ タプル [ str 、 ... ] ] )–
explicit_parentheses ( bool )–
- リターンタイプ
Union [jinja2.nodes.Tuple、jinja2.nodes.Expr]
- class jinja2.lexer.TokenStream(generator, name, filename)
トークンストリームは、トークンを生成する反復可能です。 ただし、パーサーはそれを反復処理せず、
next()
を呼び出して1つのトークンを先に進めます。 現在アクティブなトークンは current として保存されます。- パラメーター
ジェネレーター( Iterable [ jinja2.lexer.Token ] )–
名前(オプション [ str ] )–
ファイル名(オプション [ str ] )–
- current
現在のトークン。
- __next__()
トークンを1つ先に進めて、古いトークンを返します。
これを直接呼び出す代わりに、組み込みの
next()
を使用してください。- リターンタイプ
- property eos: bool
私たちはストリームの終わりにいますか?
- expect(expr)
指定されたトークンタイプを期待して返します。 これは、 jinja2.lexer.Token.test()と同じ引数を受け入れます。
- パラメーター
expr ( str )–
- リターンタイプ
- look()
次のトークンを見てください。
- リターンタイプ
- next_if(expr)
トークンテストを実行し、一致した場合はトークンを返します。 それ以外の場合、戻り値は None です。
- パラメーター
expr ( str )–
- リターンタイプ
オプション[ jinja2.lexer.Token ]
- push(token)
トークンをストリームにプッシュバックします。
- パラメーター
トークン( jinja2.lexer.Token )–
- リターンタイプ
なし
- skip(n=1)
先にn個のトークンを取得しました。
- パラメーター
n ( int )–
- リターンタイプ
なし
- skip_if(expr)
next_if()と同様ですが、 True または False のみを返します。
- パラメーター
expr ( str )–
- リターンタイプ
ブール
- class jinja2.lexer.Token(lineno, type, value)
- パラメーター
lineno ( int )–
タイプ( str )–
値( str )–
- lineno
トークンの行番号
- type
トークンのタイプ。 この文字列はインターンされているため、
is
演算子を使用して任意の文字列と比較できます。
- value
トークンの値。
- test(expr)
トークン式に対してトークンをテストします。 これは、トークンタイプまたは
'token_type:token_value'
のいずれかです。 これは、文字列の値と型に対してのみテストできます。- パラメーター
expr ( str )–
- リターンタイプ
ブール
- test_any(*iterable)
複数のトークン式に対してテストします。
- パラメーター
反復可能( str )–
- リターンタイプ
ブール
レクサーモジュールには、文字列内の改行文字をカウントできるユーティリティ関数もあります。
- jinja2.lexer.count_newlines(value)
- 文字列内の改行文字の数を数えます。 これは、ストリームをフィルタリングする拡張機能に役立ちます。
- パラメーター
- 値( str )–
- リターンタイプ
- int
AST
AST(抽象構文木)は、解析後のテンプレートを表すために使用されます。 コンパイラが実行可能なPythonコードオブジェクトに変換するのはノードのビルドです。 カスタムステートメントを提供する拡張機能は、ノードを返してカスタムPythonコードを実行できます。
以下のリストは、現在利用可能なすべてのノードについて説明しています。 ASTはJinjaバージョン間で変更される可能性がありますが、下位互換性は維持されます。
詳細については、 jinja2.Environment.parse()のreprを参照してください。
- exception jinja2.nodes.Impossible
- ノードが要求されたアクションを実行できなかった場合に発生します。