Jinja2 簡明使用手冊

介紹
Jinja是基於Python的模板引擎,功能比較類似於於PHP的smarty,J2ee的Freemarker和velocity。 

運行需求
Jinja2需要Python2.4以上的版本。 

安裝
按照Jinja有多種方式,你可以根據需要選擇不同的按照方式。 

使用easy_install安裝
使用easy_install 或pip: 
#sudo easy_install Jinja2 
#sudo pip install Jinja2 

這兩個工具可以自動從網站上下載Jinja,並安裝到python目錄的site-packages目錄中。 

從tar包安裝

# 下載Jinja的安裝包 
# 解壓縮 
# sudo python setup.py install 

基本API用法
用Jinja創建模板最簡單的方式是通過 Template. 但在實際應用中並不推薦此用法:  
<pre> 
  >>> from Jinja2 import Template 
  >>> template = Template('Hello ` name `!') 
  >>> template.render(name='World') 
  u'Hello World!' 
</pre> 
這個例子使用字符串作爲模板內容創建了一個Template實例,然後用"name='World'"作爲參數調用"render方法,將內容中 的'name'替換爲"World",最終返回渲染過的字符串--"u'Hello World!'"。 

API
Environment

Environment是Jinja2中的一個核心類,它的實例用來保存配置、全局對象,以及從本地文件系統或其它位置加載模板。 
多數應用會在初始化時創建Environment實例,然後用它來加載模板。當然,如果系統有必要使用不同的配置,也可以創建多個 Environment實例一起使用。 
配置Jinja2爲你的應用加載模板的最簡單的方式可以像下面這樣: 
  from Jinja2 import Environment, PackageLoader 
  env = Environment(loader=<script type="text/JavaScript" src="http://www.javaeye.com/javascripts/tinymce/themes/advanced/langs/zh.js"></script><script type="text/javascript" src="http://www.javaeye.com/javascripts/tinymce/plugins/javaeye/langs/zh.js"></script>PackageLoader('yourapplication', 'templates')) 
上述代碼使用缺省配置創建了一個Environment實例,並指定PackageLoader作爲模板加載器。PackageLoader可以 從你的python應用程序的包中讀取並加載模板。在之後的文檔中會逐一介紹Jinja2的加載器。 

創建了Environment實例,我們就可以加載模板了: 
  template = env.get_template('mytemplate.html') 
之後就可以跟上文中的例子一樣用render方法來渲染模板了。 
  print template.render(the='variables', Go='here') 
高級API
Environment類:

  class Environment(block_start_string='{%', block_end_string='%}', variable_start_string='{{', vari- 
  able_end_string='}}', comment_start_string='{#', comment_end_string='#}', 
  line_statement_preix=None, trim_blocks=False, extensions=(), optimized=True, 
  undefined=<class 'Jinja2.runtime.Undefined'>, finalize=None, autoescape=False, 
  loader=None) 
Environment是Jinja2的核心組件,它包含了重要的共享變量,例如:配置,過濾器,測試器,全局變量等等。Environment 的實例如果沒有被共享或者沒有加載過模板則可以進行修改,如果在加載過模板之後修改Environment實例會遇到不可知的結果。 
參數介紹: 
loader 模板加載器. 
block_start_string 塊開始標記符,缺省是 '{%'. 
block_end_string 塊結束標記符,缺省是 '%}'. 
variable_start_string 變量開始標記符,缺省是 '{{'. 
variable_start_string 變量結束標記符,缺省是 '{{'. 
comment_start_string 註釋開始標記符,缺省是 '{#'. 
comment_end_string 註釋結束標記符,缺省是 '#}'. 
通過修改上面幾個標記符參數,可以讓我們的模板變成另外一種風格,比如 
env = Environment( 
block_start_string="<#", block_end_string="#>, 
variable_start_string="${", variable_start_string="}", 
comment_start_string="<#--", comment_end_string="--#>", ...) 
這樣,我們的模板可以設計爲下面的樣子: 
<# block title #> Index <# endblock #> 
${name} 
<#-- this is comment --#> 
怎麼樣,是不是有點像freemarker的風格?但是我們不推薦這樣做,否則就無法使用Jinja的編輯器來編輯模板了。 
auto_reload 
如果設爲True,Jinja會在使用Template時檢查模板文件的狀態,如果模板有修改, 則重新加載模板。如果對性能要求較高,可以將此值設爲False。 
autoescape XML/HTML自動轉義,缺省爲false. 就是在渲染模板時自動把變量中的<>&等字符轉換爲&lt;&gt;&amp;。 
cache_size 
    緩存大小,缺省爲50,即如果加載超過50個模板,那麼則保留最近使用過多50個模板,其它會被刪除。如果換成大小設爲0,那麼所有模板都會在使用時被重 編譯。如果不希望清除緩存,可以將此值設爲-1. 
undefined Undefined或者其子類,用來表現模板中未定義的值 
使用過freemarker的朋友應該知道,在freemarker中模板中使用值爲null的變量時會看到一個“很黃很暴力”的一堆錯誤棧信息。有些人 對freemarker的這種處理方式不以爲然,因爲這樣還需要對變量值加入判斷,處理起來比較繁瑣。而另一個比較有名氣的模板引擎Velocity則會 忽略空值,例如在Velocity中打印值爲null的變量將會得到一個空字符。 
Jinja通過設置不同的undefined參數來得到類似Freemarker或者Velocity的處理方式。 

line_statement_prefix 指定行級語句的前綴. 
extensions Jinja的擴展的列表,可以爲導入到路徑字符串或者表達式類 

Template類
Template類是Jinja的另一個重要的組件,它可以被看作是一個編譯過的模板文件,被用來產生目標文本. 

Template類的構建器參數和Environment類基本相同, 區別是,創建Template實例需要一個模板文本參數,另外它不需要loader參數。 
Template實例是一個不可變對象,即你不能修改Template實例的屬性。 

一般情況下,我們會使用Environment實例來創建Template,但也可以直接使用Template構建器來創建。如果要用構建器來創 建Template實例,那麼Jinja會根據構建器參數自動爲此Template創建/指派一個內部Environment實例,凡是使用相同構建器參 數(不包括模板文本串參數)創建的Template實例都會共享同一個內部Environment實例。 
方法: 
<pre>render(*args, **kwargs)</pre> 
此方法接受與“dict”相同的構建器參數:一個dict,dict的子類,或者一些關鍵字參數。下面兩種調用方式是等價的: 
template.render(knights='that say nih') 
template.render({'knights': 'that say nih'}) 

<pre>generate(*args, **kwargs)</pre> 
此方法會一段一段的渲染模板,而不是一次性的將整個模板渲染成目標文本。這對產生非常大的模板時非常有用。調用此方法會返回一個產生器 (generator),它可以.... 
<pre>stream(*args, **kwargs)</pre> 
與generate功能類似,只不過此方法返回一個TemplateStream module 
此方法用來在模板運行時導入, 也可以用來在python代碼中訪問導出的模板變量. 
  >>> t = Template('{% macro foo() %}42{% endmacro %}23') 
  >>> unicode(t.module) 
  u'23' 
  >>> t.module.foo() 
  u'42'. 
Undened Types 未定義類型
Undened及其子類類被用來作爲未定義類型。Environment的構建器可以指定undefined參數,它可以是undefined types中的任意一個,或者是Undefined的子類。當模板引擎無法找到一個名稱或者一個屬性時,使用的Undefined會決定哪些操作可以正常 進行,哪些不可以。 
'''class Undefined(hint=None, obj=None, name=None)''' 
缺省undefined類型。此未定義類型可以打印或者作爲sequence迭代。但是不能做其它操作,否則會拋出UndefinedError 
<pre> 
foo = Undefined(name='foo') 
  >>> str(foo) 
  '' 
  >>> not foo 
True 
  >>> foo + 42 
Traceback (most recent call last): 
... 
Jinja2.exceptions.UndefinedError: 'foo' is undefined 
</pre> 

'''class DebugUndefined(hint=None, obj=None, name=None)''' 
<pre> 
  >>> foo = DebugUndefined(name='foo') 
  >>> str(foo) 
'` foo `' 
  >>> not foo 
True 
  >>> foo + 42 
Traceback (most recent call last): 
... 
Jinja2.exceptions.UndefinedError: 'foo' is undefined 
</pre> 

'''class StrictUndefined(hint=None, obj=None, name=None)''' 
<pre> 
  >>> foo = StrictUndefined(name='foo') 
  >>> str(foo) 
Traceback (most recent call last): 
... 
Jinja2.exceptions.UndefinedError: 'foo' is undefined 
  >>> not foo 
Traceback (most recent call last): 
... 
Jinja2.exceptions.UndefinedError: 'foo' is undefined 
  >>> foo + 42 
Traceback (most recent call last): 
... 
Jinja2.exceptions.UndefinedError: 'foo' is undefined 
</pre> 

Loaders 加載器
加載器負責從某些位置(比如本地文件系統)中加載模板,並維護在內存中的被編譯過的模塊。 

文件系統加載器,它可以從本地文件系統中查找並加載模板: 
  class FileSystemLoader(searchpath, encoding='utf-8', cache_size=50, auto_reload=True) 
第一個參數searchpath是查找路徑,它可以是一個路徑字符串,也可以是保護多個路徑的sequence。 

  >>> loader = FileSystemLoader('/path/to/templates') 
  >>> loader = FileSystemLoader(['/path/to/templates', '/other/path']) 

包加載器。它可以從python包中加載模板: 
  class PackageLoader(package_name, package_path='templates', encoding='utf-8', cache_size=50, auto_reload=True) 
  >>> loader = PackageLoader('mypackage', 'views') 

字典加載器。在mapping參數中明確指定模板文件名的路徑。它用來做單元測試比較有用: 
  class DictLoader(mapping, cache_size=50, auto_reload=False) 
  >>> loader = DictLoader({'index.html': 'source here'}) 

函數加載器。讓指定的函數來返回模板文件的路徑。 
  class FunctionLoader(load_func, cache_size=50, auto_reload=True) 
  >>> def load_template(name): 
  ... if name == 'index.html' 
  ... return '...' 
  ... 
  >>> loader = FunctionLoader(load_template) 


前綴加載。如果你的工程中包含很多應用,那麼多應用之間模板名稱就可能存在命名衝突的問題。使用前綴加載器可以有效的解決不同應用之間模板命名衝 突問題。 
  class PrefixLoader(mapping, delimiter='/', cache_size=50, auto_reload=True) 


  >>> loader = PrefixLoader({ 
  ... 'app1': PackageLoader('mypackage.app1'), 
  ... 'app2': PackageLoader('mypackage.app2') 
  ... }) 

如此,如果要使用app1中的模板,可以get_template('app1/xxx.html'), 使用app2的模板,可以使用get_template('app2/xxx.html')。delimiter字符決定前綴和模板名稱之間的分隔符,默 認爲'/'。 

選擇加載器,與PrefixLoader類似,可以組合多個加載器。當它在一個子加載器中查找不到模板時,它會在下一個子加載器中繼續查找。如果 你要用一個不同的位置覆蓋內建模板時非常有用 
  class ChoiceLoader(loaders, cache_size=50, auto_reload=True) 

  >>> loader = ChoiceLoader([ 
  ... FileSystemLoader('/path/to/user/templates'), 
  ... PackageLoader('myapplication') 


所有加載都繼承自BaseLoader,如果你要實現一個自定義加載可以,可以寫一個BaseLoader的子類,並覆蓋get_source方 法。 

  class BaseLoader(cache_size=50, auto_reload=True) 

一個簡單的例子 

  from Jinja2 import BaseLoader, TemplateNotFound 
  from os.path import join, exists, getmtime 
  class MyLoader(BaseLoader): 
      def __init__(self, path, cache_size=50, auto_reload=True): 
          BaseLoader.__init__(self, cache_size, auto_reload) 
          self.path = path 
      def get_source(self, environment, template): 
          path = join(self.path, template) 
              if not exists(path): 
                  raise TemplateNotFound(template) 
                  mtime = getmtime(path) 
                  with file(path) as f: 
                      source = f.read().decode('utf-8') 
                      return source, path, lambda: mtime != getmtime(path) 
  get_source(environment, template) 
  load(environment, name, globals=None) 
加載一個模板。此方法會在緩存中查找模板,如果緩存中不存在則調用get_source得到模板的內容,緩存後返回結果。 

注意,BaseLoader已經實現了load方法,它對模板的緩存進行了處理。如果你不需要自己維護緩存,則不必重寫此方法。 

Utilites

用來幫助你添加自定義過濾器或者函數到Jinja中 
  environmentfilter(f) 
  contextfilter(f) 
  environmentfunction(f) 
  contextfunction(f) 
  escape(s) 
  class Markup() 

異常

類名描述
class TemplateError()所有模板異常的基類
class UndefinedError()操作一個未定義對象時
class TemplateNotFound(name)模板未找到
class TemplateSyntaxError(message, lineno, name)模板語法錯誤


模板設計文檔

概述


一個模板其實就是一個普通的文本文件。它可以被設計爲任何文本格式(HTML,XML,CSV等等)。它也不需要確定的擴展名,不過一般我們都會 用'.html'或'.xml' 
模板中包含變量,表達式,標籤,變量和表達式會在模板渲染時被用值來替換,標籤控制模板的邏輯。Jinja的語法主要參考自Django和 python。 

下面是一個簡單的模板,它包含的了幾個模板中的基本元素,在之後的文檔中會對這些元素做詳細說明。 
<pre> 
  <!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> 
</pre> 
這個模板中包含了兩種標記符"{% ... %}"與"` `.``.` `", 前者用來執行一個循環或者一個賦值語句,後者用來打印一個變量。 

變量

你可以傳遞python的變量給模板,用來替換模板中的標記。這些變量可以是任何Python對象。在模板中可以直接操作傳入的變量對象,也可以 訪問這些變量的屬性。 
訪問變量屬性有兩種方式,一種是用"obj.attr"的方式,另一種是類似字典的方式:"obj['attr']". 
<pre> 
  ` foo`.`bar ` 
  {{ foo['bar'] }} 
</pre> 
注意,上面的'` `.``.` `是Jinja的用來打印變量標記。如果要在其它標籤中訪問變量,則不能在變量名旁邊加花括號。 

過濾器(filters)
變量可以在模板中被過濾器修改. 使用過濾器的方式比較類似管道(pipe)操作。如: 
<pre>  '{{ name|striptags|title }}'</pre> 
這個例子的意思是:將name變量用striptags消除變量值中的tag(用<>括起來的內容),再用title過濾器將首字符 大寫。 

過濾器也可以接受參數,用起來比較像調用函數 
<pre> '{{ list|join(', ') }}'</pre> 

內建過濾器介紹參見內建過濾器一節。 

檢查器(Tests)

檢查器用來在Jinja的if塊裏面檢查一個變量是否符合某種條件。它的用法是 varname is atest, 例如檢查一個變量是否存在 
  {% if name is defined %} 
這裏, defined就是一個檢查器。 
檢查器跟過濾器一樣,也可以有參數,如果檢查器只有一個參數,可以不寫括號,直接用一個空格將檢查器名和參數隔開,如下例中,兩行代碼的作用是一 樣的: 
  {% if loop.index is divisibleby 3 %} 
  {% if loop.index is divisibleby(3) %} 

在後面的內建檢查器列表一節中會介紹各個內建檢查器 


註釋
Jinja中可以加入註釋,如: 
  {# note: disabled template because we no longer user this 
      {% for user in users %} 
        ... 
      {% endfor %} 
  #} 
這些註釋內容不會出現在模板產生的文本中。 

模板繼承

模板繼承是Jinja中一個非常有用的功能。這個功能允許你創建一個包含有所有公共元素的頁面基本骨架,在子模板中可以重用這些公用的元素。 
使用模板繼承其實很簡單,下面我們開始用一個例子來介紹模板繼承的用法。 

基礎模板

我們首先寫一個名爲"base.html"的模板,它包含下面的內容: 
<pre> 
<!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 %} 
        &copy; Copyright 2008 by <a href="http://domain.invalid/">you</a>. 
        {% endblock %} 
    </div> 
</body> 
</pre> 
在這個模板中有很多'block', 這些block中間的內容,我們將會在子模板中用其它內容替換。 

子模板

我們再寫一個名爲"child.html"的模板,內容如下: 
<pre> 
{% 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 awsome homepage. 
    </p> 
{% endblock %} 
</pre> 
:在這個模板的第一行,我們用{% extends "base.html" %}標明,這個模板將繼承base.html. 
在隨後的內容中包含了很多跟base.html中相同的block,如title,content,這些block中的內容將會替換 base.html的內容後輸出. 

:extends後面的模板名稱的寫法依賴於此模板使用的模板加載器, 比如如果要使用FileSystemLoader,你可以在模板文件名中加入文件的文件夾名,如: 
<pre> 
{% extends "layout/default.html" %} 
</pre> 
在base.html中,我們定義了block “footer”,這個block在子模板中沒有被重定義,那麼Jinja會直接使用父模板中的內容輸出。 

另外要注意,在同一個模板中不能定義名稱相同的block。 

如果你要在模板中多次打印同一個block,可以用用self變量加上block的名字: 
<pre> 
<title>{% block title %}{% endblock %}</title> 
<h1>{{ self.title() }}</h1> 
{% block body %}{% endblock %} 
</pre> 
和Python不同的地方是,Jinja不支持多繼承。 

super block
如果要在子模板中重寫父模板的block中打印被重寫的block的內容,可以調用super關鍵字。 
<pre> 
{% block sidebar %} 
    <h3>Table Of Contents</h3> 
    ... 
    {{ super() }} 
{% endblock %} 
<pre> 
HTML轉義
:我們傳遞給模板的變量中可能會有一些html標記符,這些標記符也許會影響我們頁面的正常顯示,而且會給我們的站點帶來跨站腳本***的隱患。 
Jinja提供了兩種方式-自動或者手工來對變量值進行html轉義,即把'<'轉換爲'&lt;','>'轉換爲 '&gt;','&'轉換爲'&amp;' 
通過給Environment或Template的構建器傳遞autoescape參數,可以設置自動轉義與否。 
手動轉義
這種方式需要我們使用過濾器轉換我們需要轉義的變量 
'{{ user.username|e }}'. 這裏'e'就是轉義過濾器 

自動轉義
這種方式會在打印變量時自動進行轉義。除非使用'safe'過濾器標明不需要轉義: 
<pre> 
'{{ user.username|safe }}'. 
</pre> 
結構控制標記

Jinja中的控制標記包括:條件判斷標記(if/elif/else),循環控制(for-loop),另外還有macro(宏)和上文中提到 的block。 

for
循環打印一個序列,例如: 
<pre> 
<h1>Members</h1> 
<ul> 
{% for user in users %} 
  <li>{{ user.username|e }}</li> 
{% endfor %} 
</ul> 
</pre> 
在循環內部,你可以訪問一些特殊的變量

VariableDescription
loop.index當 前迭代的索引,從1開始算
loop.index0當前迭代的索引,從0開始算
loop.revindex相 對於序列末尾的索引,從1開始算
loop.revindex0相對於序列末尾的索引,從0開始算
loop.first相 當於 loop.index == 1.
loop.last相當於 loop.index == len(seq) - 1
loop.length序列的長度.
loop.cycle是 一個幫助性質的函數,可以接受兩個字符串參數,如果當前循環索引是偶數,則顯示第一個字符串,是奇數則顯示第二個字符串。它常被在表格中用來用不同的背景 色區分相鄰的行。


<pre> 

{% for row in rows %} 
    <li class="{{ loop.cycle('odd', 'even') }}">` row `</li> 
{% endfor %} 
</pre> 
需要注意的是,Jinja的循環不支持break和continue標記。你可以對需要迭代的sequence使用過濾器來達到與break和 continue相同的目的。 
下面的例子中,如果user.hidden屬性爲true的則continue 
<pre> 
{% for user in users if not user.hidden %} 
    <li>{{ user.username|e }}</li> 
{% endfor %} 
</pre> 
Jinja的for語句有一個和python相同的用法,那就是“else':當無循環時顯示else中的內容,如下例: 
<pre> 
<ul> 
{% for user in users %} 
    <li>{{ user.username|e }}</li> 
{% else %} 
    <li><em>no users found</em></li> 
{% endif %} 
</ul> 
</pre> 
if

if語句用來在Jinja中做比較判斷,比較常見的用法是判斷一個變量是否已定義,是否非空,是否爲true 
<pre> 
{% if users %} 
<ul> 
{% for user in users %} 
    <li>{{ user.username|e }}</li> 
{% endfor %} 
</ul> 
{% endif %} 
</pre> 
和python一樣,也可以使用elif和else 
<pre> 
{% if kenny.sick %} 
    Kenny is sick. 
{% elif kenny.dead %} 
    You killed Kenny!  You bastard!!! 
{% else %} 
    Kenny looks okay --- so far 
{% endif %} 
</pre> 
if語句也可以被用來做內聯表達式或者for語句過濾器。 

宏(Macro)
宏的作用和函數比較類似。用來把一部分常用的代碼封裝起來,避免重複性的工作。 
宏可以定義在一個幫助性質的模板中,用imported的方式被其它模板引用;也可以在模板中定義並直接使用。這兩種方式有個顯著的不同:在模板 中定義的宏可以訪問傳給模板的上下文變量;在其它模板中定義的宏則只能訪問到傳遞給它的變量,或者全局變量。 

這裏有個打印表單元素的簡單的宏 
<pre> 
{% macro input(name, value='', type='text', size=20) -%} 
    <input type="` type `" name="` name `" value="{{ 
        value|e }}" size="` size `"> 
{%- endmacro %} 
</pre> 
這個宏可以在命名空間中被直接調用 
<pre> 
<p>{{ input('username') }}</p> 
<p>{{ input('password', type='password') }}</p> 
</pre> 
如果這個宏在其它模板中,你必須先用import引入。 
在一個模板中你可以訪問三種特殊變量: 

*'''varargs''' 等同於python語法中的"*args" 
*'''kwargs''' 等同於python語法中的"**kwargs" 
*'''caller''' 被call標籤調用的宏,調用者會被存儲在一個叫做caller的變量中。 

宏其實也是一個對象,它有一些屬性可以在模板中使用: 
*'''name''' 宏的名稱。{{ 'input.name':string }} 
*'''arguments''' 宏可以接受的參數,這個屬性是一個元組 
*'''defaults''' 缺省值的元組 
*'''catch_kwargs''' 這個宏是否可以接受關鍵字參數 
*'''catch_varargs''' 這個宏是否可以接受索引位置參數 
*'''caller''' 是否有caller變量,可以被call標籤調用 

Call

在某些情況下,你可能需要將一個宏對象傳遞到另外一個宏中使用。爲了實現此目的,你可以使用call block。 
<pre> 
{% 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 %} 
</pre> 
在這裏例子裏,我們用"call render_dialog"調用了宏render_dialog,其中,'hello world作爲render_dialog的title參數。在render_dialog中用{{ caller() }}將 call block中的內容顯示出來。 

在使用 {{ caller() }} 時,也可以傳入參數,如下例: 
<pre> 
{% 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 %} 
</pre> 

賦值
在一個代碼塊內部你可以爲一個變量賦值。在塊(block, macro, loop)外部賦值的變量可以被從模板中導出,提供給其它模板使用。 
一個賦值語句的用法如下例: 
<pre> 
{% navigation = [('index.html', 'Index'), ('about.html', 'About')] %} 
</pre> 
include
用include可以導入另外一個模板到當前模板中 
<pre> 
{% include 'header.html' %} 
Body 
{% include 'footer.html' %} 
</pre> 
import

Jinja2支持將常用的代碼放到宏中。這些宏可以放到不同的模板中,然後用import語句導入來使用,這有點類似python的import 功能。需要注意的是,import導入的模板會被緩存,而且導入到模板不能訪問當前模板的本地變量,它只能訪問全局變量。 

導入模板有兩種方式,一是導入整個的模板作爲一個變量,另一個方法是從一個模板中導入指定的宏或者可導出的變量 
下面我們寫一個名爲"form.html"的模板, 這個模板作爲一個公共模板提供給其它模板使用 
<pre> 
{% 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 %} 
</pre> 
最簡單和靈活的方式是把form.html整個導入到一個模板中 
<pre> 
{% 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> 
</pre> 
或者導入指定的內容(宏或者變量)到當前模板中 
<pre> 
{% 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> 
</pre> 
表達式

Jinja的表達式在模板中到處都是,它的語法很類似python,而且它很簡單,即使不會python也可以很容易學會它。 

字面值

字面值是最簡單的表達式,它其實就是一個python的對象,在Jinja中有下面幾種字面值: 
字符串,數字,序列,元組,字典,bool類型。 

它們的用法很python的很接近,如下面的例子: 
<pre> 
<ul> 
{% for href, caption in [('index.html', 'Index'), ('about.html', 'About'), 
                         ('downloads.html', 'Downloads')] %} 
    <li><a href="` href `">` caption `</a></li> 
{% endfor %} 
</ul> 
</pre> 
數字計算

Jinja支持一下幾種操作符: 
+,-,/,//(整除),%求餘,*乘,**次方 

邏輯操作
Jinja支持一下幾種邏輯操作符,它們可以放在if塊中使用: 
and, or, not, () 

其它操作符
'''in ''' 
判斷一個對象是否存在於另一個序列或者元組中 
<pre> 
{{ 1 in [1, 2, 3] }} 
</pre> 
'''is''' 
執行一個檢查器 
'''|''' 
執行一個過濾器 
'''~''' 
連接字符串 '{{ "Hello " ~ name ~ "!" }}',如果name的值是'world, 顯示的內容將是 "Hello world" 
'''( )''' 調用函數 
'''. / []''' 訪問一個對象的屬性 

if表達式
Jinja支持內聯表達式,在某些情況下非常有用,例如: 
<pre> 
{% extends layout_template if layout_template is defined else 'master.html' %} 
</pre> 
這個例子的意思是:如果變量layout_template已定義則導入,否則導入master.html 
通用的語法規則是'''<do something> if <something is true> else <do something else>''' 


內建過濾器

*'''abs(number)''' 返回數字的絕對值 

*'''batch(value, linecount, fill_with=None)''' 
:將一個序列以給定值分成若干片,如果給定了fill_with,則會將fill_with補充到未分配的部分。比如一個序列 ['a','b','c','d','e'], 用數值3分片將會得到[['a','b','c'], ['d','e']], 如果分片時指定fill_with='&nbsp;',結果將會是[['a','b','c'], ['d','e','&nbsp;']] 
:這個過濾器的用處在於,如果你要在表格中顯示一個很長的序列,每行顯示5個,則可以用下面的方式打印: 
<pre> 
{% for row in seq|batch(3, '&nbsp;') %} 
{% for item in row %} 
</pre> 
*'''capitalize(s)''' 
首字符大寫 
*'''center(value, width=80)''' 
生成一個長度爲width的空字符串,將value放在中間 
*'''default(value, default_value=u”, boolean=False)''' 
如果value未定義,則顯示default_value,如果value是一個bool型,需要將boolean置爲true,這樣當value爲 false是將會打印缺省值 
這個過濾器的別名是d 
*'''dictsort(value, case_sensitive=False, by='key')''' 
字典排序,case_sensitive決定是否大小寫敏感,by決定是按照key排序還是按value排序 
*'''escape(s)''' 
html字符轉義,別名是e 
*'''filesizeformat(value)''' 
將一個大數字轉換成KMG形式,如:1.3k,34g,25.3m等等 

*'''first(seq)''' 
返回序列的第一個值 
*'''float(value, default=0.0)''' 
將一個值轉換成浮點數,如果轉換失敗則返回default 
*'''forceescape(value)''' 
不管value是否被轉義過,一律進行html轉義。比如value="<", 如果用“value|e|e”則會得到“&lt;",而不是"&amp;lt;",如果用forceescape則會得 到"&amp;lt;" 

*'''format(value, *args, **kwargs)''' 
等同於python的"%s,%s" % (str1, str2) 
*'''groupby(value, attribute)''' 
類似SQL的group by,可以將一個序列裏的對象/字典,按照attribute分組。如下例: 
<pre> 
<ul> 
{% for group in persons|groupby('gender') %} 
    <li>` group`.`grouper `<ul> 
    {% for person in group.list %} 
        <li>` person`.`first_name ` ` person`.`last_name `</li> 
    {% endfor %}</ul></li> 
{% endfor %} 
</ul> 
</pre> 
也可以用下面的方式使用: 
<pre> 
<ul> 
{% for grouper, list in persons|groupby('gender') %} 
    ... 
{% endfor %} 
</ul> 
</pre> 
"grouper"是分組的值,在上面的例子中分別是“male”和“female” 
*'''indent(s, width=4, indentfirst=False)''' 
將文本s中每行的首字符縮進width個字符。indentfirst表示是否縮進第一行。 
*'''int(value, default=0)''' 
將value轉換成整數,如果轉換失敗則返回default 
*'''join(seq, d=u”)''' 
將序列seq中的各個值用d字符連接起來形成一個字符串。 
*'''last(seq)''' 
序列的最後一個值。 
*'''length(object)''' 
序列或者字典的長度 
別名:count 
*'''list(value)''' 
將value轉換爲序列,如果value是字符串,則將字符串轉換爲字符數組。 
*'''lower(s)''' 
將字符串轉換爲小寫 
*'''pprint(value, verbose=False)''' 
debug時使用,可以打印變量的詳細信息。 
*'''random(seq)''' 
隨機從序列中取得一個值。 

*'''replace(s, old, new, count=None)''' 
將字符s中的old字符串替換爲new字符串,如果給定了count,則最多替換count次。 
*'''reverse(value)''' 
將一個序列反轉。 
*'''round(value, precision=0, method='common')''' 
浮點數求精。precision是小數點位數,method有common,ceil,floor三種。common是四捨五入,ceil和floor與 python的同名函數功能相同。 
*'''safe(value)''' 
如果當前模板設置了html自動轉義,用此過濾器可以使value不轉義 
*'''slice(value, slices, fill_with=None)''' 
將序列分片,用fill_with字符填充最後一組子序列長度不足的部分。 
*'''sort(value, reverse=False)''' 
將序列按從小到大排序,reverse爲true則按從大到小排序 
*'''string(object)''' 
將一個對象轉換爲unicode字符串 
*'''striptags(value)''' 
去掉字符串value中的html,xml標籤 
*'''sum(sequence, start=0)''' 
統計數值序列的和。start表示從第幾項開始計算 
*'''title(s)''' 
將字符串s中每個單詞首字符大寫 

*'''trim(value)''' 
去掉字符串value中首尾的空格 

*'''truncate(s, length=255, killwords=False, end='...')''' 
截斷一個字符串爲length長度,末尾補end字符。killword爲false則將最後一個單詞完整保留,爲True則將嚴格按照給定的長度截斷。 
*'''upper(s)''' 
將字符串轉換爲大寫 
*'''urlize(value, trim_url_limit=None, nofollow=False)''' 

*'''wordcount(s)''' 
統計字符串中單詞的個數 
*'''wordwrap(s, pos=79, hard=False)''' 
將字符串s按照pos長度換行。如果hard爲True,則強制截斷單詞。 
*'''xmlattr(d, autospace=True)''' 
創建一個sgml/xml的屬性字符串,例如: 
<pre> 
<ul{{ {'class': 'my_list', 'missing': none, 'id': 'list-%d'|format(variable)}|xmlattr }}> 
... 
</ul> 
</pre> 
結果會是這個樣子: 
<pre> 
<ul class="my_list" id="list-42"> 
... 
</ul> 
</pre> 
值會自動進行html轉義,如果爲未定義或者None則忽略。 
*'''autospace''': 自動在首部添加空格. 

內建檢查器
*'''callable(object)''' 
對象是否可調用 
*'''defined(value)''' 
對象是否已定義 
*'''divisibleby(value, num)''' 
value是否可以被num整除 
*'''escaped(value)''' 
是否已轉義 
*'''even(value)''' 
是否爲奇數 
*'''iterable(value)''' 
是否可以循環 
*'''lower(value)''' 
是否爲小寫 
*'''none(value)''' 
是否爲None 
*'''number(value)''' 
是否爲數字 
*'''odd(value)''' 
是否爲偶數 
*'''sameas(value, other)''' 
value是否與other爲同一個對象實例 
*'''sequence(value)''' 
是否爲序列 
*'''string(value)''' 
是否是字符串 
*'''undefined(value)''' 
是否未定義 
*'''upper(value)''' 
是否爲大寫


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章