介紹
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. 就是在渲染模板時自動把變量中的<>&等字符轉換爲<>&。
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()
異常
javascript
類名 | 描述 |
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 %}
© 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轉義,即把'<'轉換爲'<','>'轉換爲 '>','&'轉換爲'&'
經過給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>
在循環內部,你能夠訪問一些特殊的變量php
Variable | Description |
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=' ',結果將會是[['a','b','c'], ['d','e',' ']]
:這個過濾器的用處在於,若是你要在表格中顯示一個很長的序列,每行顯示5個,則能夠用下面的方式打印:
<pre>
{% for row in seq|batch(3, ' ') %}
{% 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;",若是用forceescape則會得 到"&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)'''
是否爲大寫css