擴展?
Jinja支持可以添加額外過濾器、測試、全局參數甚至擴展解析器的擴展。擴展的主要動機是將經常使用的代碼移到可重用的類中,比如添加對國際化的支持。
添加擴展名?
擴展將在創建時添加到Jinja環境中。一旦創建了環境,就不能添加其他擴展。若要添加擴展,請傳遞擴展類列表或 extensions
的參數 Environment
建造師。以下示例創建加載了i18n擴展的Jinja環境:
jinja_env = Environment(extensions=['jinja2.ext.i18n'])
i18n擴展?
進口名稱: jinja2.ext.i18n
i18n擴展可與 gettext 或 Babel . 當它被啟用時,Jinja提供了一個 trans
語句,該語句將塊標記為可翻譯并調用 gettext
.
啟用后,應用程序必須提供 gettext
和 ngettext
函數,全局或呈現時。A _()
函數作為別名添加到 gettext
功能。
環境方法?
啟用擴展后,環境提供以下附加方法:
- jinja2.Environment.install_gettext_translations(translations, newstyle=False)?
為環境全局安裝翻譯。這個
translations
對象必須實現gettext
和ngettext
.gettext.NullTranslations
,gettext.GNUTranslations
和 Babel 的STranslations
支持。Changelog
在 2.5 版本發生變更: 添加了新樣式的gettext支持。
- jinja2.Environment.install_null_translations(newstyle=False)?
不安裝op gettext函數。如果您想為國際化準備應用程序,但又不想實現完整的系統,那么這很有用。
Changelog
在 2.5 版本發生變更: 添加了新樣式的gettext支持。
- jinja2.Environment.install_gettext_callables(gettext, ngettext, newstyle=False)?
安裝給定的
gettext
和ngettext
可進入環境。他們應該表現得一模一樣gettext.gettext()
和gettext.ngettext()
.如果
newstyle
被激活時,可調用文件被包裝為像newStyle可調用文件一樣工作。見 新樣式Gettext 更多信息。Changelog
在 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
中介紹了模板設計器的擴展 the template documentation .
空白剪裁?
Changelog
在 2.10 版本加入.
內 {{% trans %}}
塊,可以很有用地修剪換行符和空白,使文本塊看起來像是翻譯文件中帶有單個空格的簡單字符串。
可以通過啟用 ext.i18n.trimmed
policy .
新樣式Gettext?
Changelog
在 2.5 版本加入.
新樣式的gettext調用的類型更少,更不容易出錯,并且更好地支持自動轉義。
您可以通過設置 env.newstyle_gettext = True
或路過 newstyle=True
到 env.install_translations
. 它們完全受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) }}
新風格 gettext
使格式化成為調用的一部分,并在幕后強制實現更高的一致性。
{{ gettext("Hello, World!") }}
{{ gettext("Hello, %(name)s!", name=name) }}
{{ ngettext("%(num)d apple", "%(num)d apples", apples|count) }}
newstyle gettext的優點是:
沒有單獨的格式化步驟,您不必記住使用
|format
過濾器。只允許使用命名占位符。這解決了翻譯人員面臨的一個常見問題,因為位置占位符不能有意義地切換位置。命名占位符總是攜帶關于值的語義信息。
即使不使用占位符,也會使用字符串格式,這使得所有字符串都使用一致的格式。記住要將任何原始百分比符號
%%
,如100%%
.翻譯后的字符串被標記為安全的,格式化根據需要執行轉義。將參數標記為
|safe
如果它已經逃走了。
循環控制?
進口名稱: jinja2.ext.loopcontrols
此擴展添加了對 break
和 continue
在循環中。在啟用之后,Jinja提供了這兩個關鍵字,它們的工作方式與Python中完全相同。
調試擴展?
進口名稱: jinja2.ext.debug
添加一個 {{% debug %}}
標記以轉儲當前上下文以及可用的篩選器和測試。這對于在不設置調試器的情況下查看模板中可使用的內容非常有用。
正在寫入擴展名?
通過編寫擴展,您可以向Jinja添加自定義標記。這是一項非常重要的任務,通常不需要,因為默認標記和表達式涵蓋了所有常見的用例。i18n擴展是說明擴展為何有用的一個很好的例子。另一個是碎片緩存。
在編寫擴展時,您必須記住,您使用的是Jinja模板編譯器,它不會驗證傳遞給它的節點樹。如果AST的格式不正確,您將得到各種各樣的編譯器或運行時錯誤,這些錯誤很難調試。始終確保正確使用創建的節點。下面的API文檔顯示了存在哪些節點以及如何使用它們。
擴展示例?
隱藏物?
以下示例實現了 cache
使用 cachelib 類庫:
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()
解析對 _()
無需使用gettext函數的Jinja靜態塊。
<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 1:
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: Environment)?
擴展可用于在解析器級別向Jinja模板系統添加額外的功能。自定義擴展已綁定到環境,但不能在上存儲特定于環境的數據 self . 原因是,通過創建副本并重新分配 environment 屬性。
由于擴展是由環境創建的,因此它們不能接受任何配置參數。人們可能希望通過使用工廠函數來解決這個問題,但這是不可能的,因為擴展是由它們的導入名稱標識的。配置擴展的正確方法是在環境中存儲配置值。因為這樣環境最終會充當中央配置存儲,所以屬性可能會發生沖突,這就是為什么擴展必須確保它們為配置選擇的名稱不是太通用的原因。
prefix
例如,一個糟糕的名字,fragment_cache_prefix
另一方面是一個好名字,包括擴展名(片段緩存)。- identifier?
擴展的標識符。這始終是擴展類的真正導入名稱,不得更改。
- tags?
如果擴展實現自定義標記,則這是擴展正在偵聽的一組標記名。
- attr(name: str, lineno: Optional[int] = None) ExtensionAttribute ?
返回當前擴展名的屬性節點。這對于將擴展上的常量傳遞給生成的模板代碼很有用。
self.attr('_my_attribute', lineno=lineno)
- call_method(name: str, args: Optional[List[Expr]] = None, kwargs: Optional[List[Keyword]] = None, dyn_args: Optional[Expr] = None, dyn_kwargs: Optional[Expr] = None, lineno: Optional[int] = None) Call ?
調用擴展的方法。這是一個快捷方式
attr()
+jinja2.nodes.Call
.
- filter_stream(stream: TokenStream) Union[TokenStream, Iterable[Token]] ?
它通過了
TokenStream
可用于篩選返回的令牌。此方法必須返回Token
S,但它不必返回TokenStream
.
語法分析器?
分析器傳遞給 Extension.parse()
提供分析不同類型表達式的方法。擴展可以使用以下方法:
- class jinja2.parser.Parser(environment: Environment, source: str, name: Optional[str] = None, filename: Optional[str] = None, state: Optional[str] = None)?
這是Jinja使用的中心解析類。它被傳遞給擴展,可以用來解析表達式或語句。
- name?
模板的加載名稱。
- stream?
- fail(msg: str, lineno: ~typing.Optional[int] = None, exc: ~typing.Type[~jinja2.exceptions.TemplateSyntaxError] = <class 'jinja2.exceptions.TemplateSyntaxError'>) te.NoReturn ?
提出的便利方法 exc 通過消息,傳遞的行號或最后一個行號以及當前名稱和文件名。
- free_identifier(lineno: Optional[int] = None) InternalName ?
返回新的自由標識符為
InternalName
.
- parse_assign_target(with_tuple: bool = True, name_only: bool = False, extra_end_rules: Optional[Tuple[str, ...]] = None, with_namespace: bool = False) Union[NSRef, Name, Tuple] ?
分析分配目標。由于Jinja允許對元組賦值,所以這個函數可以解析所有允許的賦值目標。解析對元組的默認賦值,但可以通過設置 with_tuple 到 False . 如果只需要指定姓名 name_only 可以設置為 True . 這個 extra_end_rules 參數被轉發到元組分析函數。如果 with_namespace 如果啟用,則可以分析命名空間分配。
- parse_expression(with_condexpr: bool = True) Expr ?
分析表達式。默認情況下,如果 with_condexpr 參數設置為 False 未分析條件表達式。
- parse_statements(end_tokens: Tuple[str, ...], drop_needle: bool = False) List[Node] ?
將多個語句解析到一個列表中,直到到達其中一個結束標記為止。這用于分析語句體,因為它還分析模板數據(如果適用)。解析器首先檢查當前標記是否是冒號,如果有冒號,則跳過它。然后它檢查塊的結尾并分析直到 end_tokens 達到。默認情況下,調用結束時流中的活動令牌是匹配的結束令牌。如果不需要的話 drop_needle 可以設置為 True 并刪除結束標記。
- parse_tuple(simplified: bool = False, with_condexpr: bool = True, extra_end_rules: Optional[Tuple[str, ...]] = None, explicit_parentheses: bool = False) Union[Tuple, Expr] ?
工作原理類似 parse_expression 但如果多個表達式用逗號分隔
Tuple
節點已創建。如果找不到逗號,此方法還可以返回正則表達式而不是元組。默認的分析模式是一個完整的元組。如果 simplified 是 True 只分析名稱和文本。這個 no_condexpr 參數被轉發到
parse_expression()
.因為元組不需要分隔符,可能以偽逗號結尾,所以需要額外的提示來標記元組的結尾。例如,循環支持介于 for 和 in . 在這種情況下, extra_end_rules 設置為
['name:in']
.explicit_parentheses 如果分析是由括號中的表達式觸發的,則為true。這用于確定空元組是否為有效表達式。
- class jinja2.lexer.TokenStream(generator: Iterable[Token], name: Optional[str], filename: Optional[str])?
令牌流是生成
Token
但是,解析器不會對它進行迭代,而是調用next()
先轉到一個令牌。當前活動令牌存儲為current
.- expect(expr: str) Token ?
期望給定的令牌類型并返回它。這接受了與
jinja2.lexer.Token.test()
.
- class jinja2.lexer.Token(lineno, type, value)?
- lineno?
令牌的行號
- type?
令牌的類型。此字符串已實習,因此可以使用
is
操作員。
- value?
令牌的值。
lexer模塊中還有一個實用程序函數,可以計算字符串中的換行符:
AST?
AST(抽象語法樹)用于表示解析后的模板。它是由節點組成的,然后編譯器將這些節點轉換為可執行的python代碼對象。提供定制語句的擴展可以返回節點來執行定制的python代碼。
下面的列表描述了當前可用的所有節點。AST可能會在Jinja版本之間改變,但會保持向后兼容。
有關更多信息,請查看 jinja2.Environment.parse()
.
- class jinja2.nodes.Node?
所有Jinja節點的基類。有許多不同類型的節點可用。主要有四種類型:
所有節點都有字段和屬性。字段可以是其他節點、列表或任意值。字段作為常規位置參數傳遞給構造函數,屬性作為關鍵字參數傳遞給構造函數。每個節點有兩個屬性: lineno (節點的行號)和 environment . 這個 environment 屬性在所有節點的分析過程結束時自動設置。
- find_all(node_type: Union[Type[_NodeBound], Tuple[Type[_NodeBound], ...]]) Iterator[_NodeBound] ?
查找給定類型的所有節點。如果類型是元組,則對任何元組項執行檢查。
- iter_child_nodes(exclude: Optional[Container[str]] = None, only: Optional[Container[str]] = None) Iterator[Node] ?
循環訪問節點的所有直接子節點。這將遍歷所有字段,并生成它們的值作為節點。如果字段值是列表,則返回該列表中的所有節點。
- iter_fields(exclude: Optional[Container[str]] = None, only: Optional[Container[str]] = None) Iterator[Tuple[str, Any]] ?
此方法迭代所有定義的字段并生成
(key, value)
元組。默認情況下,會返回所有字段,但可以通過提供 only 參數或排除一些使用 exclude 參數。兩者都應該是字段名的集合或元組。
- set_ctx(ctx: str) Node ?
重置節點和所有子節點的上下文。默認情況下,解析器將生成所有具有“加載”上下文的節點,因為它是最常見的節點。此方法在解析器中用于將分配目標和其他節點設置為存儲上下文。
- set_environment(environment: Environment) Node ?
為所有節點設置環境。
- class jinja2.nodes.Expr?
所有表達式的基類。
- 節點類型
- as_const(eval_ctx: Optional[EvalContext] = None) Any ?
以常量或升序返回表達式的值
Impossible
如果不可能的話。安
EvalContext
如果沒有給定任何上下文,則可以提供。創建的默認上下文要求節點具有附加的環境。Changelog
在 2.4 版本發生變更: 這個 eval_ctx 已添加參數。
- class jinja2.nodes.Filter(node, name, args, kwargs, dyn_args, dyn_kwargs)?
將過濾應用于表達式。
name
是過濾的名稱,其他字段與Call
。如果
node
是None
,過濾正在過濾擋路中使用,并應用于擋路的內容。- 節點類型
- class jinja2.nodes.Test(node, name, args, kwargs, dyn_args, dyn_kwargs)?
將測試應用于表達式。
name
是測試的名稱,其他字段與Call
。Changelog
在 3.0 版本發生變更:
as_const
共享相同的篩選器和測試邏輯。測試檢查易失性、異步和@pass_context
等等。裝修工。- 節點類型
- class jinja2.nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs)?
調用表達式。 args 是參數列表, kwargs 關鍵字參數列表(列表
Keyword
節點) dyn_args 和 dyn_kwargs 必須是 None 或用作動態位置節點的節點 (*args
)關鍵詞 (**kwargs
)參數。- 節點類型
- class jinja2.nodes.CondExpr(test, expr1, expr2)?
條件表達式(內聯if表達式)。 (
{{{{ foo if bar else baz }}}}
)- 節點類型
- class jinja2.nodes.ContextReference?
返回當前模板上下文。它可以像
Name
節點,用'load'
并將返回電流Context
對象。這里有一個將當前模板名稱賦給名為 foo ::
Assign(Name('foo', ctx='store'), Getattr(ContextReference(), 'name'))
這基本上等同于使用
pass_context()
在使用高級API時使用裝飾符,這會導致對上下文的引用作為第一個參數傳遞給函數。- 節點類型
- class jinja2.nodes.DerivedContextReference?
返回當前模板上下文,包括局部變量。行為完全像
ContextReference
,但包含局部變量,例如for
循環。Changelog
在 2.11 版本加入.
- 節點類型
- class jinja2.nodes.ExtensionAttribute(identifier, name)?
返回綁定到環境的擴展的屬性。標識符是
Extension
.通常通過調用
attr()
方法。- 節點類型
- class jinja2.nodes.ImportedName(importname)?
如果使用導入名稱創建,則在節點訪問時返回導入名稱。例如
ImportedName('cgi.escape')
返回 escape 來自CGI模塊的函數。導入由編譯器優化,因此無需將其分配給局部變量。- 節點類型
- class jinja2.nodes.InternalName(name)?
編譯器中的內部名稱。您不能自己創建這些節點,但是解析器提供了一個
free_identifier()
方法,該方法為您創建新的標識符。該標識符不能從模板中獲得,編譯器也不會對其進行特殊處理。- 節點類型
- class jinja2.nodes.Const(value)?
所有常量值。解析器將返回簡單常量(如
42
或"foo"
但它也可以用于存儲更復雜的值,如列表。只有具有安全表示形式的常量(對象eval(repr(x)) == x
是真的)。- 節點類型
- class jinja2.nodes.MarkSafeIfAutoescape(expr)?
將被包裝的表達式標記為安全的(將其包裝為 Markup )但只有當自動轉義處于活動狀態時。
Changelog
在 2.5 版本加入.
- 節點類型
- class jinja2.nodes.Name(name, ctx)?
查找名稱或在名稱中存儲值。這個 ctx 節點的值可以是以下值之一:
store :在名稱中存儲值
load :加載該名稱
param 喜歡 store 但如果名稱被定義為函數參數。
- 節點類型
- class jinja2.nodes.Block(name, body, scoped, required)?
表示塊的節點。
Changelog
在 3.0.0 版本發生變更: 這個 required 已添加字段。
- 節點類型
- class jinja2.nodes.CallBlock(call, args, defaults, body)?
就像一個沒有名字的宏,而是一個調用。 call 用未命名的宏調用為 caller
- 節點類型
- class jinja2.nodes.EvalContextModifier(options)?
修改eval上下文。對于應修改的每個選項,a
Keyword
必須添加到options
名單。示例更改 autoescape 設置:
EvalContextModifier(options=[Keyword('autoescape', Const(True))])
- 節點類型
- class jinja2.nodes.ScopedEvalContextModifier(options, body)?
修改eval上下文,稍后將其還原。工作原理和
EvalContextModifier
但只會修改EvalContext
對于中的節點body
.- 節點類型
- class jinja2.nodes.For(target, iter, body, else_, test, recursive)?
for循環。 target 是迭代的目標(通常是
Name
或Tuple
) iter 可迭代的。 body 是用作循環體的節點列表,以及 else_ 的節點列表 else 塊。如果不存在其他節點,則它必須是空列表。對于篩選的節點,表達式可以存儲為 test ,否則 None .
- 節點類型
- class jinja2.nodes.FromImport(template, names, with_context)?
表示“從導入”標記的節點。重要的是不要將不安全的名稱傳遞給name屬性。編譯器將屬性查找直接轉換為getattr調用,并執行 not 使用接口的下標回調。由于導出的變量不能以雙下劃線(解析器斷言)開頭,這對于常規的jinja代碼來說不是問題,但是如果在擴展中使用此節點,則必須格外小心。
如果需要別名,名稱列表可能包含元組。
- 節點類型
- class jinja2.nodes.Macro(name, args, defaults, body)?
宏定義。 name 是宏的名稱, args 參數列表和 defaults 默認值列表(如果有)。 body 是宏體的節點列表。
- 節點類型
- class jinja2.nodes.OverlayScope(context, body)?
擴展的覆蓋范圍。這是一個很大程度上未經優化的范圍,但是可以用來從字典或類似字典的對象將完全任意的變量引入子范圍。這個 context 字段必須計算為字典對象。
示例用法:
OverlayScope(context=self.call_method('get_context'), body=[...])
Changelog
在 2.10 版本加入.
- 節點類型
- class jinja2.nodes.With(targets, values, body)?
WITH語句的特定節點。在舊版本的Jinja中,WITH語句是在 Scope 節點代替。
Changelog
在 2.9.3 版本加入.
- 節點類型
- exception jinja2.nodes.Impossible?
在節點無法執行請求的操作時引發。