拡張機能—Jinjaドキュメント

提供:Dev Guides
Jinja/docs/3.0.x/extensions
移動先:案内検索

拡張機能

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を呼び出します。

有効にした後、アプリケーションはgettextngettext、およびオプションでpgettextnpgettextの機能をグローバルに、またはレンダリング時に提供する必要があります。 _()関数がgettext関数のエイリアスとして追加されました。

環境メソッド

拡張機能を有効にした後、環境は次の追加のメソッドを提供します。

jinja2.Environment.install_gettext_translations(translations, newstyle=False)

環境の翻訳をグローバルにインストールします。 translationsオブジェクトは、gettextngettext、およびオプションでpgettextnpgettextを実装する必要があります。 gettext.NullTranslationsgettext.GNUTranslations、および BabelTranslationsがサポートされています。

バージョン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)

指定されたgettextngettextpgettext、および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は文字列自体、または複数の引数を持つ関数の文字列のタプルです。

Babel がインストールされている場合は、 Babel を参照して文字列を抽出してください。

複数の言語で利用できるが、すべてのユーザーに同じ言語を提供する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=Trueenv.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は、拡張機能(フラグメントキャッシュ)の名前を含む適切な名前です。

パラメーター

環境jinja2.environment.Environment )–

リターンタイプ

なし

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 を発生させる便利なメソッド。

パラメーター
リターンタイプ

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

  • name_onlybool )–

  • extra_end_rulesオプション [ タプル [ str ... ] ] )–

  • with_namespacebool )–

リターンタイプ

Union [jinja2.nodes.NSRef、jinja2.nodes.Name、jinja2.nodes.Tuple]

parse_expression(with_condexpr=True)

式を解析します。 オプションの with_condexpr パラメーターが False に設定されている場合、デフォルトではすべての式が解析されます。条件式は解析されません。

パラメーター

with_condexprbool )–

リターンタイプ

jinja2.nodes.Expr

parse_statements(end_tokens, drop_needle=False)

終了トークンの1つに到達するまで、複数のステートメントをリストに解析します。 これは、必要に応じてテンプレートデータも解析するため、ステートメントの本体を解析するために使用されます。 パーサーは、現在のトークンがコロンであるかどうかを最初にチェックし、コロンがある場合はスキップします。 次に、ブロックの終わりをチェックし、 end_tokens のいずれかに到達するまで解析します。 デフォルトでは、呼び出しの終了時にストリーム内のアクティブなトークンは、一致した終了トークンです。 これが不要な場合は、 drop_needle を True に設定して、終了トークンを削除できます。

パラメーター
  • end_tokensタプル [ str ... ] [ X85X])– –

  • drop_needlebool )–

リターンタイプ

リスト[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_condexprbool )–

  • extra_end_rulesオプション [ タプル [ str ... ] ] )–

  • explicit_parenthesesbool )–

リターンタイプ

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()を使用してください。

リターンタイプ

jinja2.lexer.Token

property eos: bool

私たちはストリームの終わりにいますか?

expect(expr)

指定されたトークンタイプを期待して返します。 これは、 jinja2.lexer.Token.test()と同じ引数を受け入れます。

パラメーター

exprstr )–

リターンタイプ

jinja2.lexer.Token

look()

次のトークンを見てください。

リターンタイプ

jinja2.lexer.Token

next_if(expr)

トークンテストを実行し、一致した場合はトークンを返します。 それ以外の場合、戻り値は None です。

パラメーター

exprstr )–

リターンタイプ

オプション[ jinja2.lexer.Token ]

push(token)

トークンをストリームにプッシュバックします。

パラメーター

トークンjinja2.lexer.Token )–

リターンタイプ

なし

skip(n=1)

先にn個のトークンを取得しました。

パラメーター

nint )–

リターンタイプ

なし

skip_if(expr)

next_if()と同様ですが、 True または False のみを返します。

パラメーター

exprstr )–

リターンタイプ

ブール

class jinja2.lexer.Token(lineno, type, value)
パラメーター
  • linenoint )–

  • タイプstr )–

  • str )–

lineno

トークンの行番号

type

トークンのタイプ。 この文字列はインターンされているため、is演算子を使用して任意の文字列と比較できます。

value

トークンの値。

test(expr)

トークン式に対してトークンをテストします。 これは、トークンタイプまたは'token_type:token_value'のいずれかです。 これは、文字列の値と型に対してのみテストできます。

パラメーター

exprstr )–

リターンタイプ

ブール

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
ノードが要求されたアクションを実行できなかった場合に発生します。