jinja 模板設計者文件¶- 可以在ansible的playbook中使用

jackjack部落格發表於2018-09-20

模板設計者文件

這份文件描述了模板引擎中的語法和語義結構,對於建立Jinja 模板是一份相當有用的參考。因為模板引擎非常靈活,應用中的配置會在分隔符和未定義值的行為方面與這裡的配置有細微差異。

概要

模板僅僅是文字檔案。它可以生成任何基於文字的格式(HTML、XML、CSV、LaTex等等)。它並沒有特定的副檔名,.html.xml都是可以的。

模板包含變數表示式,這兩者在模板求值的時候會被替換為值。模板中還有標籤,控制模板的邏輯。模板語法的大量靈感來自於Django和Python 。

下面是一個最小的模板,它闡明瞭一些基礎。我們會在文件中後面的部分解釋細節:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> 
<html  lang= "en" > 
<head> 
    <title> My Webpage </title> 
</head> 
<body> 
    <ul  id = "navigation" > 
    {%  for  item  in  navigation  %} 
        <li><a  href= " {{  item.href  }} " > {{  item.caption  }} </a></li> 
    {%  endfor  %} 
    </ul>

    <h1> My Webpage </h1> 
    {{  a_variable  }} 
</body> 
</html>

這包含了預設的設定。應用開發者也會把語法從{% foo %}改成<% foo %> 或類似的東西。

這裡有兩種分隔符: {% ... %}{{ ... }}前者用於執行諸如for迴圈或賦值的語句,後者把表示式的結果列印到模板上。

變數

應用把變數傳遞到模板,你可能在模板中弄混。變數上面也可以有你能訪問的屬性或元素。變數看起來是什麼,完全取決於應用提供了什麼。

你可以使用點(.)來訪問變數的屬性,作為替代,也可以使用所謂的“下標”語法([])。下面的幾行效果是一樣的:

{{  foo.bar  }} 
{{  foo [ 'bar' ]  }}

知曉花括號不是變數的一部分,而是列印語句的一部分是重要的。如果你訪問標籤裡的不帶括號的變數。

如果變數或屬性不存在,會返回一個未定義值。你可以對這類值做什麼取決於應用的配置,預設的行為是它如果被列印,其求值為一個空字串,並且你可以迭代它,但其它操作會失敗。

實現

為方便起見,Jinja2中foo.bar在Python層中做下面的事情:

  • 檢查foo上是否有一個名為bar的屬性。
  • 如果沒有,檢查foo中是否有一個'bar'項。
  • 如果沒有,返回一個未定義物件。

foo['bar']的方式相反,只在順序上有細小差異:

  • 檢查在foo中是否有一個'bar'項。
  • 如果沒有,檢查foo上是否有一個名為bar的屬性。
  • 如果沒有,返回一個未定義物件。

如果一個物件有同名的項和屬性,這很重要。此外,有一個attr()過濾器,它只查詢屬性。

過濾器

變數可以通過過濾器修改。過濾器與變數用管道符號(|)分割,並且也可以用圓括號傳遞可選引數。多個過濾器可以鏈式呼叫,前一個過濾器的輸出會被作為後一個過濾器的輸入。

例如{{ name|striptags|title }}會移除name中的所有HTML標籤並且改寫為標題樣式的大小寫格式。過濾器接受帶圓括號的引數,如同函式呼叫。這個例子會把一個列表用逗號連線起來: {{ list|join(', ') }}

下面的內建過濾器清單節介紹了所有的內建過濾器。

測試

除了過濾器,所謂的“測試”也是可用的。測試可以用於對照普通表示式測試一個變數。要測試一個變數或表示式,你要在變數後加上一個is以及測試的名稱。例如,要得出一個值是否定義過,你可以用name is defined,這會根據name是否定義返回true或false 。

測試也可以接受引數。如果測試只接受一個引數,你可以省去括號來分組它們。例如, 下面的兩個表示式做同樣的事情:

{%  if  loop .index  is  divisibleby  3  %} 
{%  if  loop .index  is  divisibleby ( 3 )  %}

下面的內建測試清單章節介紹了所有的內建測試。

註釋

要把模板中一行的部分註釋掉,預設使用{# ... #}註釋語法。這在除錯或新增給你自己或其它模板設計者的資訊時是有用的:

{# note: disabled template because we no longer use this 
    {% for user in users %} 
        ... 
    {% endfor %} 
#}

空白控制

預設配置中,模板引擎不會對空白做進一步修改,所以每個空白(空格、製表符、換行符等等)都會原封不動返回。如果應用配置了Jinja的trim_blocks,模板標籤後的第一個換行符會被自動移除(像PHP中一樣)。

此外,你也可以手動剝離模板中的空白。當你在塊(比如一個for標籤、一段註釋或變數表示式)的開始或結束放置一個減號(-),可以移除塊前或塊後的空白:

{%  for  item  in  seq - %} 
    {{  item  }} 
{% - endfor  %}

這會產出中間不帶空白的所有元素。如果seq19的數字的列表,輸出會是123456789

如果開啟了行語句,它們會自動去除行首的空白。

提示

標籤和減號之間不能有空白。

有效的 :

{% - if  foo - %} ... {%  endif  %}

無效的 :

{% - if foo - %}... {%  endif  %}

轉義

有時想要或什至必要讓Jinja忽略部分,不會把它作為變數或塊來處理。例如,如果使用預設語法,你想在在使用把{{作為原始字串使用,並且不會開始一個變數的語法結構,你需要使用一個技巧。

最簡單的方法是在變數分隔符中({{)使用變數表示式輸出:

{{  '{{'  }}

對於較大的段落,標記一個塊為 raw是有意義的。例如展示Jinja語法的例項,你可以在模板中用這個片段:

{%  raw  %}
    <ul>
    {% for item in seq %}
        <li>{{ item }}</li>
    {% endfor %}
    </ul>
{%  endraw  %}

行語句

如果應用啟用了行語句,就可以把一個行標記為一個語句。例如如果行語句字首配置為 #,下面的兩個例子是等價的:

<ul>
# for item in seq
    <li> {{  item  }} </li>
# endfor
</ul>

<ul> 
{%  for  item  in  seq  %} 
    <li> {{  item  }} </li> 
{%  endfor  %} 
</ul>

行語句字首可以出現在一行的任意位置,只要它前面沒有文字。為了語句有更好的可讀性,在塊的開始(比如forifelif等等)以冒號結尾:

# for item in seq:
    ...
# endfor

提示

若有未閉合的圓括號、花括號或方括號,行語句可以跨越多行:

<ul>
# for href, caption in [('index.html', 'Index'),
                        ('about.html', 'About')]:
    <li><a  href= " {{  href  }} " > {{  caption  }} </a></li>
# endfor
</ul>

從Jinja 2.2開始,行註釋也可以使用了。例如如果配置##為行註釋字首,行中所有##之後的內容(不包括換行符)會被忽略:

# for item in seq:
     <li> {{  item  }} </li>      ## this comment is ignored
# endfor

模板繼承

Jinja中最強大的部分就是模板繼承。模板繼承允許你構建一個包含你站點共同元素的基本模板“骨架”,並定義子模板可以覆蓋的

聽起來複雜,實際上很簡單。從例子上手是最易於理解的。

基本模板

這個模板,我們會把它叫做base.html,定義了一個簡單的HTML骨架文件,你可能使用一個簡單的兩欄頁面。用內容填充空的塊是子模板的工作:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> 
<html  lang= "en" > 
<html  xmlns= "http://www.w3.org/1999/xhtml" > 
<head > 
    {%  block  head  %} 
    <link  rel= "stylesheet"  href= "style.css"  /> 
    <title> {%  block  title  %}{%  endblock  %} - My Webpage </title> 
    {%  endblock  %} 
< /head> 
<body> 
    <div  id= "content" >{%  block  content  %}{%  endblock %} </div> 
    <div  id= "footer" > 
        {%  block  footer  %} 
        © Copyright 2008 by <a  href= "http://domain.invalid/" > you </a> .
         {%  endblock  % } 
    </div> 
</body>

在本例中,{% block %}標籤定義了四個字幕版可以填充的塊。所有的block標籤告訴模板引擎子模板可以覆蓋模板中的這些部分。

子模板

一個子模板看起來是這樣:

{%  extends  "base.html"  %} 
{%  block  title  %} Index {%  endblock  %} 
{%  block  head  %} 
    {{  super ()  }} 
    <style type= "text/css" > 
        .important  {  color :  #336699 ;  } 
    </style> 
{%  endblock  %} 
{%  block  content  %} 
    <h1> Index </h1> 
    <p  class= "important" >
      Welcome on my awesome homepage.
    </p> 
{%  endblock  %}

{% extend %}標籤是這裡的關鍵。它告訴模板引擎這個模板“繼承”另一個模板。當模板系統對這個模板求值時,首先定位父模板。extends標籤應該是模板中的第一個標籤。它前面的所有東西都會按照普通情況列印出來,而且可能會導致一些困惑。更多該行為的細節以及如何利用它,見 Null-Master退回

模板的檔名依賴於模板載入器。例如FileSystemLoader允許你用檔名訪問其它模板。你可以使用斜線訪問子目錄中的模板:

{%  extends  "layout/default.html"  %}

這種行為也可能依賴於應用內嵌的Jinja 。注意子模板沒有定義footer塊,會使用父模板中的值。

你不能在同一個模板中定義多個同名的{% block %}標籤。因為塊標籤以兩種方向工作,所以存在這種限制。即一個塊標籤不僅提供一個可以填充的部分,也在父級定義填充的內容。如果同一個模板中有兩個同名的{% blok %}標籤,父模板無法獲知要使用哪一個塊的內容。

如果你想要多次列印一個塊,無論如何你可以使用特殊的self變數並呼叫與塊同名的函式:

<title> {%  block  title  %}{%  endblock  %} </title> 
<h1> {{  self.title ()  }} </h1> 
{%  block  body  %}{%  endblock  %}

Super塊

可以呼叫super來渲染父級塊的內容。這會返回父級塊的結果:

{%  block  sidebar  %} 
    <h3> Table Of Contents </h3>
    ...
    {{  super ()  }} 
{%  endblock  %}

命名塊結束標籤

Jinja2 允許你在塊的結束標籤中加入的名稱來改善可讀性:

{%  block  sidebar  %} 
    {%  block  inner_sidebar  %}
        ...
    {%  endblock  inner_sidebar  %} 
{%  endblock  sidebar  %}

無論如何,endblock後面的名稱一定與塊名匹配。

巢狀塊和作用域

巢狀塊可以勝任更復雜的佈局。而預設的塊不允許訪問塊外作用域中的變數:

{%  for  item  in  seq  %} 
    <li> {%  block  loop_item  %}{{  item  }}{%  endblock  %} </li> 
{%  endfor  %}

這個例子會輸出空的<li>項,因為item在塊中是不可用的。其原因是,如果塊被子模板替換,變數在其塊中可能是未定義的或未被傳遞到上下文。

從Jinja 2.2開始,你可以顯式地指定在塊中可用的變數,只需在塊宣告中新增 scoped修飾,就把塊設定到作用域中:

{%  for  item  in  seq  %} 
    <li> {%  block  loop_item  scoped  %}{{  item  }}{%  endblock  %} </li> 
{%  endfor  %}

當覆蓋一個塊時,不需要提供scoped修飾。

模板物件

Changed in version 2.4.

當一個模板物件被傳遞到模板上下文,你也可以從那個物件繼承。假設呼叫程式碼傳遞layout_template佈局模板到環境,這段程式碼會工作:

{%  extends  layout_template  %}

之前layout_template變數一定是佈局模板檔名的字串才能工作。

HTML轉義

當從模板生成HTML 時,始終有這樣的風險:變數包含影響已生成HTML 的字元。有兩種解決方法:手動轉義每個字元或預設自動轉義所有的東西。

Jinja 兩者都支援,使用哪個取決於應用的配置。預設的配置未開啟自動轉義有這樣幾個原因:

  • 轉義所有非安全值的東西也意味著Jijna 轉義已知不包含HTML 的值,比如數字,對效能有巨大影響。
  • 關於變數安全性的資訊是易碎的。可能會發生強制標記一個值為安全或非安全的情況, 而返回值會被作為HTML 轉義兩次。

使用手動轉義

如果啟用了手動轉義,按需轉義變數就是你的責任。要轉義什麼?如果你有一個可能包含><&"字元的變數,你必須轉義它,除非變數中的HTML有可信的良好格式。轉義通過用管道傳遞到過濾器|e 來實現: { { user.username|e }}

使用自動轉義

當啟用了自動轉移,預設會轉移一切,除非值被顯式地標記為安全的。可以在應用中標記,也可以在模板中使用|safe過濾器標記。這種方法的主要問題是Python本身沒有被汙染的值的概念,所以一個值是否安全的資訊會丟失。如果這個資訊丟失,會繼續轉義,你最後會得到一個轉義了兩次的內容。

但雙重轉義很容易避免,只需要依賴Jinja2 提供的工具而不使用諸如字串模運算子這樣的Python 內建結構。

返回模板資料(巨集、superself.BLOCKNAME)的函式,其返回值總是被標記為安全的。

模板中的字串字面量在自動轉義中被也被視為是不安全的。這是因為安全的字串是一個對Python 的擴充套件,而不是每個庫都能妥善地使用它。

控制結構清單

控制結構指的是所有的那些可以控制程式流的東西——條件(比如if/elif/ekse )、 for迴圈、以及巨集和塊之類的東西。控制結構在預設語法中以{% .. %}塊的形式出現。

For

遍歷序列中的每項。例如,要顯示一個由users`變數提供的使用者列表:

<h1> Members </h1> 
<ul> 
{%  for  user  in  users  %} 
  <li> {{  user.username | e  }} </li> 
{%  endfor  %} 
</ul>

因為模板中的變數保留它們的物件屬性,可以迭代像dict的容器:

<dl> 
{%  for  key ,  value  in  my_dict.iteritems ()  %} 
    <dt> {{  key | e  }} </dt> 
    <dd> {{  value | e  }} </dd> 
{%  endfor  %} 
</dl>

注意無論如何字典通常是無序的,所以你可能需要把它作為一個已排序的列表傳入到模板或使用dictsort過濾器。

在一個for 迴圈塊中你可以訪問這些特殊的變數:

變數 描述
loop.index 當前迴圈迭代的次數(從1 開始)
loop.index0 當前迴圈迭代的次數(從0 開始)
loop.revindex 到迴圈結束需要迭代的次數(從1 開始)
loop.revindex0 到迴圈結束需要迭代的次數(從0 開始)
loop.first 如果是第一次迭代,為True 。
loop.last 如果是最後一次迭代,為True 。
loop.length 序列中的專案數。
loop.cycle 在一串序列間期取值的輔助函式。見下面的解釋。

在for迴圈中,可以使用特殊的loop.cycle輔助函式,伴隨迴圈在一個字串/變數列表中週期取值:

{%  for  row  in  rows  %} 
    <li  class= " {{  loop .cycle ( 'odd' ,  'even' )  }} " > {{  row  }} </li> 
{%  endfor  %}

從Jinja 2.1開始,一個額外的cycle輔助函式允許迴圈限定外的週期取值。更多資訊請閱讀全域性函式清單

與Python中不同,模板中的迴圈內不能breakcontinue但你可以在迭代中過濾序列來跳過專案。下面的例子中跳過了所有隱藏的使用者:

{%  for  user  in  users  if  not  user.hidden  %} 
    <li> {{  user.username | e  }} </li> 
{%  endfor  %}

好處是特殊的loop可以正確地計數,從而不計入未迭代過的使用者。

如果因序列是空或者過濾移除了序列中的所有專案而沒有執行迴圈,你可以使用 else渲染一個用於替換的塊:

<ul> 
{%  for  user  in  users  %} 
    <li> {{  user.username | e  }} </li> 
{%  else  %} 
    <li><em> no users found </em></li> 
{ %  endfor  %} 
</ul>

也可以遞迴地使用迴圈。當你處理諸如站點地圖之類的遞迴資料時很有用。要遞迴地使用迴圈,你只需要在迴圈定義中加上recursive修飾,並在你想使用遞迴的地方,對可迭代量呼叫loop變數。

下面的例子用遞迴迴圈實現了站點地圖:

<ul  class= "sitemap" > 
{% - for  item  in  sitemap  recursive  %} 
    <li><a  href= " {{  item.href | e  }} " > {{  item.title  }} </a> 
    {% - if  item.children - %} 
        <ul  class= "submenu" > {{  loop ( item.children )  }} </ul> 
    {% - endif  %} </li>
{% - endfor %} 
</ul>

If

Jinja中的if語句可比Python中的if語句。在最簡單的形式中,你可以測試一個變數是否未定義,為空或false:

{%  if  users  %} 
<ul> 
{%  for  user  in  users  %} 
    <li> {{  user.username | e  }} </li> 
{%  endfor  %} 
</ul> 
{%  endif  %}

像在Python中一樣,用elifelse來構建多個分支。你也可以用更復雜的 表示式 :

{%  if  kenny.sick  %}
    Kenny is sick.
{%  elif  kenny.dead  %}
    You killed Kenny! You bastard!!!
{%  else  %}
    Kenny looks okay --- so far
{%  endif  %}

If也可以被用作內聯表示式並作為 迴圈過濾

巨集

巨集類似常規程式語言中的函式。它們用於把常用行為作為可重用的函式,取代手動重複的工作。

這裡是一個巨集渲染表單元素的小例子:

{%  macro  input ( name ,  value = '' ,  type = 'text' ,  size = 20 ) - %} 
    <input  type= " {{  type  }} "  name= " {{  name  }} "  value= " {{ 
        value | e  }} "  size= " {{  size  }} " > 
{% - endmacro  %}

在名稱空間中,巨集之後可以像函式一樣呼叫:

<p> {{  input ( 'username' )  }} </p> 
<p> {{  input ( 'password' ,  type = 'password' )  }} </p>

如果巨集在不同的模板中定義,你需要首先使用import

在巨集內部,你可以訪問三個特殊的變數:

varargs
如果有多於巨集接受的引數個數的位置引數被傳入,它們會作為列表的值儲存在 varargs變數上。
kwargs
varargs,但只針對關鍵字引數。所有未使用的關鍵字引數會儲存在這個特殊變數中。
caller
如果巨集通過call標籤呼叫,呼叫者會作為可呼叫的巨集被儲存在這個變數中。

巨集也可以暴露某些內部細節。下面的巨集物件屬性是可用的:

name
巨集的名稱。{{ input.name }}會列印input
arguments
一個巨集接受的引數名的元組。
defaults
預設值的元組。
catch_kwargs
如果巨集接受額外的關鍵字引數(也就是訪問特殊的kwargs變數),為true
catch_varargs
如果巨集接受額外的位置引數(也就是訪問特殊的varargs變數),為true
caller
如果巨集訪問特殊的caller變數且由call標籤呼叫,為true

如果一個巨集的名稱以下劃線開始,它不是匯出的且不能被匯入。

呼叫

在某些情況下,需要把一個巨集傳遞到另一個巨集。為此,可以使用特殊的call塊。下面的例子展示瞭如何讓巨集利用呼叫功能:

{%  macro  render_dialog ( title ,  class = 'dialog' ) - %} 
    <div  class= " {{  class  }} " > 
        <h2> {{  title  }} </h2> 
        <div  class= "contents" > 
            {{  caller ()  }} 
        </div> 
    </div> 
{% - endmacro  %}

{%  call  render_dialog ( 'Hello World' )  %}
    This is a simple dialog rendered by using a macro and
    a call block.
{%  endcall  %}

也可以向呼叫塊傳遞引數。這在為迴圈做替換時很有用。總而言之,呼叫塊的工作方式幾乎與巨集相同,只是呼叫塊沒有名稱。

這裡是一個帶引數的呼叫塊的例子:

{%  macro  dump_users ( users ) - %} 
    <ul> 
    {% - for  user  in  users  %} 
        <li><p> {{  user.username | e  }} </p> {{  caller ( user )  }} < /li> 
    {% - endfor  %} 
    </ul> 
{% - endmacro  %}

{%  call ( user )  dump_users ( list_of_user )  %} 
    <dl> 
        <dl> Realname </dl> 
        <dd> {{  user.realname | e  }} </dd> 
        <dl> Description </dl> 
        <dd> {{  user.description  }} </dd> 
    </dl> 
{%  endcall  %}

過濾器

過濾器段允許你在一塊模板資料上應用常規Jinja2過濾器。只需要把程式碼用 filter節包裹起來:

{%  filter  upper  %}
    This text becomes uppercase
{%  endfilter  %}

賦值

在程式碼塊中,你也可以為變數賦值。在頂層的(塊、巨集、迴圈之外)賦值是可匯出的,即可以從別的模板中匯入。

賦值使用set標籤,並且可以為多個變數賦值:

{%  set  navigation  =  [( 'index.html' ,  'Index' ),  ( 'about.html' ,  'About' )]  %} 
{%  set  key ,  value  =  call_something ()  %}

繼承

extends標籤用於從另一個模板繼承。你可以在一個檔案中使用多次繼承,但是隻會執行其中的一個。見上面的關於模板繼承的節。

塊用於繼承,同時作為佔位符和用於替換的內容。模板繼承 節中詳細地介紹了塊。

包含

include語句用於包含一個模板,並在當前名稱空間中返回那個檔案的內容渲染結果:

{%  include  'header.html'  %}
    Body
{%  include  'footer.html'  %}

被包含的模板預設可以訪問活動的上下文中的變數。更多關於匯入和包含的上下文行為見匯入上下文行為

從Jinja 2.2開始,你可以把一句include用ignore missing標記,這樣如果模板不存在,Jinja會忽略這條語句。當與withwithout context 語句聯合使用時,它必須被放在上下文可見性語句之前這裡是一些有效的例子:

{%  include  "sidebar.html"  ignore missing  %} 
{%  include  "sidebar.html"  ignore missing  with context  %} 
{%  include  "sidebar.html"  ignore missing  without context  %}

New in version 2.2.

你也可以提供一個模板列表,它會在包含前被檢查是否存在。第一個存在的模板會被包含進來。如果給出了ignore missing,且所有這些模板都不存在,會退化至不做任何渲染,否則將會丟擲一個異常。

例子:

{%  include  [ 'page_detailed.html' ,  'page.html' ]  %} 
{%  include  [ 'special_sidebar.html' ,  'sidebar.html' ]  ignore missing  %}

Changed in version 2.4:如果傳遞一個模板物件到模板上下文,你可以用include包含這個物件。

匯入

Jinja2支援在巨集中放置經常使用的程式碼。這些巨集可以被匯入,並不同的模板中使用。這與Python中的import語句類似。要知道的是,匯入量會被快取,並且預設下匯入的模板不能訪問當前模板中的非全域性變數。更多關於匯入和包含的上下文行為見 匯入上下文行為

有兩種方式來匯入模板。你可以把整個模板匯入到一個變數或從其中匯入請求特定的巨集/匯出量。

比如我們有一個渲染表單(名為forms.html)的助手模組:

{%  macro  input ( name ,  value = '' ,  type = 'text' ) - %} 
    <input  type= " {{  type  }} "  value= " {{  value | e  }} "  name= " {{  name  } } " > 
{% - endmacro  %}

{% - macro  textarea ( name ,  value = '' ,  rows = 10 ,  cols = 40 ) - %} 
    <textarea  name= " {{  name  }} "  rows= " {{  rows  }} "  cols= " {{  cols 
        }} " > {{  value | e  }} </textarea> 
{% - endmacro  %}

最簡單靈活的方式是把整個模組匯入為一個變數。這樣你可以訪問屬性:

{%  import  'forms.html'  as  forms  %} 
<dl> 
    <dt> Username </dt> 
    <dd> {{  forms.input ( 'username' )  }} </dd> 
    <dt> Password </dt> 
    <dd> {{  forms.input ( 'password' ,  type = 'password' )  }} </dd> 
</dl> 
<p> {{  forms.textarea ( 'comment' )  }} </p>

此外你也可以從模板中匯入名稱到當前的名稱空間:

{%  from  'forms.html'  import  input  as  input_field ,  textarea  %} 
<dl> 
    <dt> Username </dt> 
    <dd> {{  input_field ( 'username' )  }} </dd> 
    <dt> Password </ dt> 
    <dd> {{  input_field ( 'password' ,  type = 'password' )  }} </dd> 
</dl> 
<p> {{  textarea ( 'comment' )  }} </p>

名稱以一個或更多下劃線開始的巨集和變數是私有的,不能被匯入。

Changed in version 2.4:如果傳遞一個模板物件到模板上下文,從那個物件中匯入。

匯入上下文行為

預設下,每個包含的模板會被傳遞到當前上下文,而匯入的模板不會。這樣做的原因是匯入量不會像包含量被快取,因為匯入量經常只作容納巨集的模組。

無論如何,這當然也可以顯式地更改。通過在import/include宣告中直接新增 with contextwithout context,當前的上下文可以傳遞到模板,而且不會自動禁用快取。

這裡有兩個例子:

{%  from  'forms.html'  import  input  with context  %} 
{%  include  'header.html'  without context  %}

提示

在Jinja 2.0 中,被傳遞到被包含模板的上下文不包含模板中定義的變數。事實上,這不能工作:

{%  for  box  in  boxes  %} 
    {%  include  "render_box.html"  %} 
{%  endfor  %}

在Jinja 2.0中,被包含的模板render_box.html 不能訪問 box從Jinja 2.1開始,render_box.html 可以這麼做。

表示式

Jinja 中到處都允許使用基本表示式。這像常規的Python 一樣工作,即使你不用Python 工作,你也會感受到其帶來的便利。

字面量

表示式最簡單的形式就是字面量。字面量表示諸如字串和數值的Python 物件。下面的字面量是可用的:

“Hello World”:
雙引號或單引號中間的一切都是字串。無論何時你需要在模板中使用一個字串(比如函式呼叫、過濾器或只是包含或繼承一個模板的引數),它們都是有用的。
42 / 42.23:
直接寫下數值就可以建立整數和浮點數。如果有小數點,則為浮點數,否則為整數。記住在Python裡,4242.0是不一樣的。
['list', 'of', 'objects']:

一對中括號括起來的東西是一個列表。列表用於儲存和迭代序列化的資料。例如你可以容易地在for 迴圈中用列表和元組建立一個連結的列表:

<ul> 
{%  for  href ,  caption  in  [( 'index.html' ,  'Index' ),  ( 'about.html' ,  'About' ), 
                         ( 'downloads.html' ,  'Downloads' )]  %} 
    < li><a  href= " {{  href  }} " > {{  caption  }} </a></li> 
{%  endfor  %} 
</ul>
('tuple', 'of', 'values'):
元組與列表類似,只是你不能修改元組。如果元組中只有一個項,你需要以逗號結尾它。元組通常用於表示兩個或更多元素的項。更多細節見上面的例子。
{'dict': 'of', 'key': 'and', 'value': 'pairs'}:
Python中的字典是一種關聯鍵和值的結構。鍵必須是唯一的,並且鍵必須只有一個值。字典在模板中很少使用,罕用於諸如xmlattr()過濾器之類。
true / false:
true 永遠是true ,而false 始終是false 。

提示

特殊常量truefalsenone實際上是小寫的。因為這在過去會導致混淆,過去True擴充套件為一個被認為是false的未定義的變數。所有的這三個常量也可以被寫成首字母大寫(TrueFalseNone)。儘管如此,為了一致性(所有的Jinja識別符號是小寫的),你應該使用小寫的版本。

算術

Jinja 允許你用計算值。這在模板中很少用到,但是為了完整性允許其存在。支援下面的運算子:

+
把兩個物件加到一起。通常物件是素質,但是如果兩者是字串或列表,你可以用這種方式來銜接它們。無論如何這不是首選的連線字串的方式!連線字串見~ 運算子。{{ 1 + 1 }}等於2
-
用第一個數減去第二個數。{{ 3 - 2 }}等於1
/
對兩個數做除法。返回值會是一個浮點數。 {{ 1 / 2 }}等於{{ 0.5 }}
//
對兩個數做除法,返回整數商。 {{ 20 // 7 }}等於2
%
計算整數除法的餘數。{{ 11 % 7 }}等於4
*
用右邊的數乘左邊的運算元。{{ 2 * 2 }}會返回4也可以用於重複一個字串多次。{{ '=' * 80 }}會列印80個等號的橫條。
**
取左運算元的右運算元次冪。{{ 2**3 }}會返回8

比較

==
比較兩個物件是否相等。
!=
比較兩個物件是否不等。
>
如果左邊大於右邊,返回true
>=
如果左邊大於等於右邊,返回true
<
如果左邊小於右邊,返回true
<=
如果左邊小於等於右邊,返回true

邏輯

對於if語句,在for過濾或if表示式中,它可以用於聯合多個表示式:

and
如果左運算元和右運算元同為真,返回true 。
or
如果左運算元和右運算元有一個為真,返回true 。
not
對一個表示式取反(見下)。
(expr)
表示式組。

提示

is in運算子同樣支援使用中綴記法: foo is not bar foo not in bar而不是 not foo is bar not foo in bar所有的其它表示式需要字首記法 not (foo and bar)

其它運算子

下面的運算子非常有用,但不適用於其它的兩個分類:

in
執行序列/對映包含檢查。如果左運算元包含於右運算元,返回true 。比如 {{ 1 in [1,2,3] }}會返回true 。
is
執行一個測試
|
應用一個過濾器
~
把所有的運算元轉換為字串,並且連線它們。 {{ "Hello " ~ name ~ "!" }}會返回(假設name值為 ''John'Hello John!
()
呼叫一個可呼叫量: {{ post.render() }}在圓括號中,你可以像在python中一樣使用位置引數和關鍵字引數: {{ post.render(user, full=true) }}
. / []
獲取一個物件的屬性。(見變數

If表示式

同樣,也可以使用內聯的if表示式。這在某些情況很有用。例如你可以用來在一個變數定義的情況下才繼承一個模板,否則繼承預設的佈局模板:

{%  extends  layout_template  if  layout_template  is  defined  else  'master.html'  %}

一般的語法是<do something> if <something is true> else <do something else>

else部分是可選的。如果沒有顯式地提供else塊,會求值一個未定義物件:

{{ '[%s]' % page.title if page.titl

相關文章