介紹 Jinja是基于python的模板引擎,功能比較類似于于PHP的smarty,,J2ee的Freemarker和velocity。 運行需求 Jinja2需要Python2.4以上的版本,。 安裝 按照Jinja有多種方式,,你可以根據(jù)需要選擇不同的按照方式。 使用easy_install安裝 使用easy_install 或pip: #sudo easy_install Jinja2 #sudo pip install Jinja2 這兩個工具可以自動從網(wǎng)站上下載Jinja,并安裝到python目錄的site-packages目錄中,。 從tar包安裝 # 下載Jinja的安裝包 # 解壓縮 # sudo python setup.py install 基本API用法 用Jinja創(chuàng)建模板最簡單的方式是通過 Template. 但在實際應(yīng)用中并不推薦此用法: <pre> >>> from Jinja2 import Template >>> template = Template('Hello {{ name }}!') >>> template.render(name='World') u'Hello World!' </pre> 這個例子使用字符串作為模板內(nèi)容創(chuàng)建了一個Template實例,,然后用"name='World'"作為參數(shù)調(diào)用"render方法,將內(nèi)容中 的'name'替換為"World",,最終返回渲染過的字符串--"u'Hello World!'",。 API Environment Environment是Jinja2中的一個核心類,它的實例用來保存配置,、全局對象,,以及從本地文件系統(tǒng)或其它位置加載模板。 多數(shù)應(yīng)用會在初始化時創(chuàng)建Environment實例,,然后用它來加載模板,。當(dāng)然,如果系統(tǒng)有必要使用不同的配置,,也可以創(chuàng)建多個 Environment實例一起使用,。 配置Jinja2為你的應(yīng)用加載模板的最簡單的方式可以像下面這樣: from Jinja2 import Environment, PackageLoader env = Environment(loader=<script type="text/javascript" src="http://www./javascripts/tinymce/themes/advanced/langs/zh.js"></script><script type="text/javascript" src="http://www./javascripts/tinymce/plugins/javaeye/langs/zh.js"></script>PackageLoader('yourapplication', 'templates')) 上述代碼使用缺省配置創(chuàng)建了一個Environment實例,并指定PackageLoader作為模板加載器,。PackageLoader可以 從你的python應(yīng)用程序的包中讀取并加載模板,。在之后的文檔中會逐一介紹Jinja2的加載器。 創(chuàng)建了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實例會遇到不可知的結(jié)果。 參數(shù)介紹: loader 模板加載器. block_start_string 塊開始標記符,,缺省是 '{%'. block_end_string 塊結(jié)束標記符,,缺省是 '%}'. variable_start_string 變量開始標記符,缺省是 '{{'. variable_start_string 變量結(jié)束標記符,,缺省是 '{{'. comment_start_string 注釋開始標記符,,缺省是 '{#'. comment_end_string 注釋結(jié)束標記符,缺省是 '#}'. 通過修改上面幾個標記符參數(shù),,可以讓我們的模板變成另外一種風(fēng)格,,比如 env = Environment( block_start_string="<#", block_end_string="#>, variable_start_string="${", variable_start_string="}", comment_start_string="<#--", comment_end_string="--#>", ...) 這樣,我們的模板可以設(shè)計為下面的樣子: <# block title #> Index <# endblock #> ${name} <#-- this is comment --#> 怎么樣,,是不是有點像freemarker的風(fēng)格,?但是我們不推薦這樣做,否則就無法使用Jinja的編輯器來編輯模板了,。 auto_reload 如果設(shè)為True,,Jinja會在使用Template時檢查模板文件的狀態(tài),如果模板有修改,, 則重新加載模板,。如果對性能要求較高,可以將此值設(shè)為False,。 autoescape XML/HTML自動轉(zhuǎn)義,,缺省為false. 就是在渲染模板時自動把變量中的<>&等字符轉(zhuǎn)換為<>&。 cache_size 緩存大小,,缺省為50,,即如果加載超過50個模板,那么則保留最近使用過多50個模板,,其它會被刪除,。如果換成大小設(shè)為0,那么所有模板都會在使用時被重 編譯,。如果不希望清除緩存,,可以將此值設(shè)為-1. undefined Undefined或者其子類,用來表現(xiàn)模板中未定義的值 使用過freemarker的朋友應(yīng)該知道,,在freemarker中模板中使用值為null的變量時會看到一個“很黃很暴力”的一堆錯誤棧信息,。有些人 對freemarker的這種處理方式不以為然,,因為這樣還需要對變量值加入判斷,處理起來比較繁瑣,。而另一個比較有名氣的模板引擎Velocity則會 忽略空值,,例如在Velocity中打印值為null的變量將會得到一個空字符。 Jinja通過設(shè)置不同的undefined參數(shù)來得到類似Freemarker或者Velocity的處理方式,。 line_statement_prefix 指定行級語句的前綴. extensions Jinja的擴展的列表,,可以為導(dǎo)入到路徑字符串或者表達式類 Template類 Template類是Jinja的另一個重要的組件,它可以被看作是一個編譯過的模板文件,,被用來產(chǎn)生目標文本. Template類的構(gòu)建器參數(shù)和Environment類基本相同, 區(qū)別是,,創(chuàng)建Template實例需要一個模板文本參數(shù),另外它不需要loader參數(shù),。 Template實例是一個不可變對象,,即你不能修改Template實例的屬性。 一般情況下,,我們會使用Environment實例來創(chuàng)建Template,但也可以直接使用Template構(gòu)建器來創(chuàng)建,。如果要用構(gòu)建器來創(chuàng) 建Template實例,,那么Jinja會根據(jù)構(gòu)建器參數(shù)自動為此Template創(chuàng)建/指派一個內(nèi)部Environment實例,凡是使用相同構(gòu)建器參 數(shù)(不包括模板文本串參數(shù))創(chuàng)建的Template實例都會共享同一個內(nèi)部Environment實例,。 方法: <pre>render(*args, **kwargs)</pre> 此方法接受與“dict”相同的構(gòu)建器參數(shù):一個dict,,dict的子類,或者一些關(guān)鍵字參數(shù),。下面兩種調(diào)用方式是等價的: template.render(knights='that say nih') template.render({'knights': 'that say nih'}) <pre>generate(*args, **kwargs)</pre> 此方法會一段一段的渲染模板,,而不是一次性的將整個模板渲染成目標文本。這對產(chǎn)生非常大的模板時非常有用,。調(diào)用此方法會返回一個產(chǎn)生器 (generator),它可以.... <pre>stream(*args, **kwargs)</pre> 與generate功能類似,,只不過此方法返回一個TemplateStream module 此方法用來在模板運行時導(dǎo)入, 也可以用來在python代碼中訪問導(dǎo)出的模板變量. >>> t = Template('{% macro foo() %}42{% endmacro %}23') >>> unicode(t.module) u'23' >>> t.module.foo() u'42'. Unde?ned Types 未定義類型 Unde?ned及其子類類被用來作為未定義類型。Environment的構(gòu)建器可以指定undefined參數(shù),,它可以是undefined types中的任意一個,,或者是Undefined的子類。當(dāng)模板引擎無法找到一個名稱或者一個屬性時,,使用的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 加載器 加載器負責(zé)從某些位置(比如本地文件系統(tǒng))中加載模板,,并維護在內(nèi)存中的被編譯過的模塊,。 文件系統(tǒng)加載器,,它可以從本地文件系統(tǒng)中查找并加載模板: class FileSystemLoader(searchpath, encoding='utf-8', cache_size=50, auto_reload=True) 第一個參數(shù)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參數(shù)中明確指定模板文件名的路徑,。它用來做單元測試比較有用: class DictLoader(mapping, cache_size=50, auto_reload=False) >>> loader = DictLoader({'index.html': 'source here'}) 函數(shù)加載器。讓指定的函數(shù)來返回模板文件的路徑,。 class FunctionLoader(load_func, cache_size=50, auto_reload=True) >>> def load_template(name): ... if name == 'index.html' ... return '...' ... >>> loader = FunctionLoader(load_template) 前綴加載,。如果你的工程中包含很多應(yīng)用,那么多應(yīng)用之間模板名稱就可能存在命名沖突的問題,。使用前綴加載器可以有效的解決不同應(yīng)用之間模板命名沖 突問題,。 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類似,,可以組合多個加載器,。當(dāng)它在一個子加載器中查找不到模板時,它會在下一個子加載器中繼續(xù)查找,。如果 你要用一個不同的位置覆蓋內(nèi)建模板時非常有用 class ChoiceLoader(loaders, cache_size=50, auto_reload=True) >>> loader = ChoiceLoader([ ... FileSystemLoader('/path/to/user/templates'), ... PackageLoader('myapplication') 所有加載都繼承自BaseLoader,,如果你要實現(xiàn)一個自定義加載可以,可以寫一個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) 加載一個模板。此方法會在緩存中查找模板,,如果緩存中不存在則調(diào)用get_source得到模板的內(nèi)容,,緩存后返回結(jié)果。 注意,,BaseLoader已經(jīng)實現(xiàn)了load方法,,它對模板的緩存進行了處理。如果你不需要自己維護緩存,,則不必重寫此方法,。 Utilites 用來幫助你添加自定義過濾器或者函數(shù)到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) |
模板語法錯誤 |
模板設(shè)計文檔 概述 一個模板其實就是一個普通的文本文件。它可以被設(shè)計為任何文本格式(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> 這個模板中包含了兩種標記符"{% ... %}"與"{{ .. }}", 前者用來執(zhí)行一個循環(huán)或者一個賦值語句,,后者用來打印一個變量。 變量 你可以傳遞python的變量給模板,,用來替換模板中的標記,。這些變量可以是任何Python對象。在模板中可以直接操作傳入的變量對象,,也可以 訪問這些變量的屬性,。 訪問變量屬性有兩種方式,一種是用"obj.attr"的方式,,另一種是類似字典的方式:"obj['attr']". <pre> {{ foo.bar }} {{ foo['bar'] }} </pre> 注意,,上面的'{{ .. }}是Jinja的用來打印變量標記。如果要在其它標簽中訪問變量,,則不能在變量名旁邊加花括號。 過濾器(filters) 變量可以在模板中被過濾器修改. 使用過濾器的方式比較類似管道(pipe)操作,。如: <pre> '{{ name|striptags|title }}'</pre> 這個例子的意思是:將name變量用striptags消除變量值中的tag(用<>括起來的內(nèi)容),,再用title過濾器將首字符 大寫。 過濾器也可以接受參數(shù),,用起來比較像調(diào)用函數(shù) <pre> '{{ list|join(', ') }}'</pre> 內(nèi)建過濾器介紹參見內(nèi)建過濾器一節(jié),。 檢查器(Tests) 檢查器用來在Jinja的if塊里面檢查一個變量是否符合某種條件。它的用法是 varname is atest, 例如檢查一個變量是否存在 {% if name is defined %} 這里,, defined就是一個檢查器,。 檢查器跟過濾器一樣,也可以有參數(shù),,如果檢查器只有一個參數(shù),,可以不寫括號,直接用一個空格將檢查器名和參數(shù)隔開,,如下例中,,兩行代碼的作用是一 樣的: {% if loop.index is divisibleby 3 %} {% if loop.index is divisibleby(3) %} 在后面的內(nèi)建檢查器列表一節(jié)中會介紹各個內(nèi)建檢查器 注釋 Jinja中可以加入注釋,如: {# note: disabled template because we no longer user this {% for user in users %} ... {% endfor %} #} 這些注釋內(nèi)容不會出現(xiàn)在模板產(chǎn)生的文本中,。 模板繼承 模板繼承是Jinja中一個非常有用的功能,。這個功能允許你創(chuàng)建一個包含有所有公共元素的頁面基本骨架,,在子模板中可以重用這些公用的元素。 使用模板繼承其實很簡單,,下面我們開始用一個例子來介紹模板繼承的用法,。 基礎(chǔ)模板 我們首先寫一個名為"base.html"的模板,它包含下面的內(nèi)容: <pre> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <html xmlns="http://www./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://valid/">you</a>. {% endblock %} </div> </body> </pre> 在這個模板中有很多'block', 這些block中間的內(nèi)容,,我們將會在子模板中用其它內(nèi)容替換,。 子模板 我們再寫一個名為"child.html"的模板,內(nèi)容如下: <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. 在隨后的內(nèi)容中包含了很多跟base.html中相同的block,如title,content,,這些block中的內(nèi)容將會替換 base.html的內(nèi)容后輸出. :extends后面的模板名稱的寫法依賴于此模板使用的模板加載器, 比如如果要使用FileSystemLoader,你可以在模板文件名中加入文件的文件夾名,如: <pre> {% extends "layout/default.html" %} </pre> 在base.html中,,我們定義了block “footer”,這個block在子模板中沒有被重定義,那么Jinja會直接使用父模板中的內(nèi)容輸出,。 另外要注意,,在同一個模板中不能定義名稱相同的block。 如果你要在模板中多次打印同一個block,,可以用用self變量加上block的名字: <pre> <title>{% block title %}{% endblock %}</title> <h1>{{ self.title() }}</h1> {% block body %}{% endblock %} </pre> 和Python不同的地方是,,Jinja不支持多繼承。 super block 如果要在子模板中重寫父模板的block中打印被重寫的block的內(nèi)容,,可以調(diào)用super關(guān)鍵字,。 <pre> {% block sidebar %} <h3>Table Of Contents</h3> ... {{ super() }} {% endblock %} <pre> HTML轉(zhuǎn)義 :我們傳遞給模板的變量中可能會有一些html標記符,這些標記符也許會影響我們頁面的正常顯示,,而且會給我們的站點帶來跨站腳本攻擊的隱患,。 Jinja提供了兩種方式-自動或者手工來對變量值進行html轉(zhuǎn)義,即把'<'轉(zhuǎn)換為'<',,'>'轉(zhuǎn)換為 '>',,'&'轉(zhuǎn)換為'&' 通過給Environment或Template的構(gòu)建器傳遞autoescape參數(shù),可以設(shè)置自動轉(zhuǎn)義與否,。 手動轉(zhuǎn)義 這種方式需要我們使用過濾器轉(zhuǎn)換我們需要轉(zhuǎn)義的變量 '{{ user.username|e }}'. 這里'e'就是轉(zhuǎn)義過濾器 自動轉(zhuǎn)義 這種方式會在打印變量時自動進行轉(zhuǎn)義,。除非使用'safe'過濾器標明不需要轉(zhuǎn)義: <pre> '{{ user.username|safe }}'. </pre> 結(jié)構(gòu)控制標記 Jinja中的控制標記包括:條件判斷標記(if/elif/else),循環(huán)控制(for-loop),另外還有macro(宏)和上文中提到 的block,。 for 循環(huán)打印一個序列,,例如: <pre> <h1>Members</h1> <ul> {% for user in users %} <li>{{ user.username|e }}</li> {% endfor %} </ul> </pre> 在循環(huán)內(nèi)部,你可以訪問一些特殊的變量
Variable |
Description |
loop.index |
當(dāng) 前迭代的索引,,從1開始算 |
loop.index0 |
當(dāng)前迭代的索引,,從0開始算 |
loop.revindex |
相 對于序列末尾的索引,從1開始算 |
loop.revindex0 |
相對于序列末尾的索引,,從0開始算 |
loop.first |
相 當(dāng)于 loop.index == 1. |
loop.last |
相當(dāng)于 loop.index == len(seq) - 1 |
loop.length |
序列的長度. |
loop.cycle |
是 一個幫助性質(zhì)的函數(shù),,可以接受兩個字符串參數(shù),,如果當(dāng)前循環(huán)索引是偶數(shù),則顯示第一個字符串,,是奇數(shù)則顯示第二個字符串,。它常被在表格中用來用不同的背景 色區(qū)分相鄰的行。 |
<pre> {% for row in rows %} <li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li> {% endfor %} </pre> 需要注意的是,,Jinja的循環(huán)不支持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':當(dāng)無循環(huán)時顯示else中的內(nèi)容,如下例: <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語句也可以被用來做內(nèi)聯(lián)表達式或者for語句過濾器,。 宏(Macro) 宏的作用和函數(shù)比較類似。用來把一部分常用的代碼封裝起來,,避免重復(fù)性的工作,。 宏可以定義在一個幫助性質(zhì)的模板中,用imported的方式被其它模板引用,;也可以在模板中定義并直接使用,。這兩種方式有個顯著的不同:在模板 中定義的宏可以訪問傳給模板的上下文變量;在其它模板中定義的宏則只能訪問到傳遞給它的變量,,或者全局變量,。 這里有個打印表單元素的簡單的宏 <pre> {% macro input(name, value='', type='text', size=20) -%} <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}"> {%- endmacro %} </pre> 這個宏可以在命名空間中被直接調(diào)用 <pre> <p>{{ input('username') }}</p> <p>{{ input('password', type='password') }}</p> </pre> 如果這個宏在其它模板中,你必須先用import引入,。 在一個模板中你可以訪問三種特殊變量: *'''varargs''' 等同于python語法中的"*args" *'''kwargs''' 等同于python語法中的"**kwargs" *'''caller''' 被call標簽調(diào)用的宏,調(diào)用者會被存儲在一個叫做caller的變量中,。 宏其實也是一個對象,,它有一些屬性可以在模板中使用: *'''name''' 宏的名稱。{{ 'input.name':string }} *'''arguments''' 宏可以接受的參數(shù),,這個屬性是一個元組 *'''defaults''' 缺省值的元組 *'''catch_kwargs''' 這個宏是否可以接受關(guān)鍵字參數(shù) *'''catch_varargs''' 這個宏是否可以接受索引位置參數(shù) *'''caller''' 是否有caller變量,,可以被call標簽調(diào)用 Call 在某些情況下,你可能需要將一個宏對象傳遞到另外一個宏中使用,。為了實現(xiàn)此目的,,你可以使用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"調(diào)用了宏render_dialog,,其中,,'hello world作為render_dialog的title參數(shù)。在render_dialog中用{{ caller() }}將 call block中的內(nèi)容顯示出來,。 在使用 {{ caller() }} 時,,也可以傳入?yún)?shù),如下例: <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> 賦值 在一個代碼塊內(nèi)部你可以為一個變量賦值,。在塊(block, macro, loop)外部賦值的變量可以被從模板中導(dǎo)出,,提供給其它模板使用。 一個賦值語句的用法如下例: <pre> {% navigation = [('index.html', 'Index'), ('about.html', 'About')] %} </pre> include 用include可以導(dǎo)入另外一個模板到當(dāng)前模板中 <pre> {% include 'header.html' %} Body {% include 'footer.html' %} </pre> import Jinja2支持將常用的代碼放到宏中,。這些宏可以放到不同的模板中,,然后用import語句導(dǎo)入來使用,這有點類似python的import 功能,。需要注意的是,,import導(dǎo)入的模板會被緩存,而且導(dǎo)入到模板不能訪問當(dāng)前模板的本地變量,,它只能訪問全局變量,。 導(dǎo)入模板有兩種方式,一是導(dǎo)入整個的模板作為一個變量,,另一個方法是從一個模板中導(dǎo)入指定的宏或者可導(dǎo)出的變量 下面我們寫一個名為"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整個導(dǎo)入到一個模板中 <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> 或者導(dǎo)入指定的內(nèi)容(宏或者變量)到當(dāng)前模板中 <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也可以很容易學(xué)會它。 字面值 字面值是最簡單的表達式,,它其實就是一個python的對象,,在Jinja中有下面幾種字面值: 字符串,數(shù)字,,序列,,元組,字典,,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> 數(shù)字計算 Jinja支持一下幾種操作符: +,-,/,//(整除),,%求余,,*乘,**次方 邏輯操作 Jinja支持一下幾種邏輯操作符,,它們可以放在if塊中使用: and, or, not, () 其它操作符 '''in ''' 判斷一個對象是否存在于另一個序列或者元組中 <pre> {{ 1 in [1, 2, 3] }} </pre> '''is''' 執(zhí)行一個檢查器 '''|''' 執(zhí)行一個過濾器 '''~''' 連接字符串 '{{ "Hello " ~ name ~ "!" }}',,如果name的值是'world, 顯示的內(nèi)容將是 "Hello world" '''( )''' 調(diào)用函數(shù) '''. / []''' 訪問一個對象的屬性 if表達式 Jinja支持內(nèi)聯(lián)表達式,在某些情況下非常有用,,例如: <pre> {% extends layout_template if layout_template is defined else 'master.html' %} </pre> 這個例子的意思是:如果變量layout_template已定義則導(dǎo)入,,否則導(dǎo)入master.html 通用的語法規(guī)則是'''<do something> if <something is true> else <do something else>''' 內(nèi)建過濾器 *'''abs(number)''' 返回數(shù)字的絕對值 *'''batch(value, linecount, fill_with=None)''' :將一個序列以給定值分成若干片,如果給定了fill_with,,則會將fill_with補充到未分配的部分,。比如一個序列 ['a','b','c','d','e'], 用數(shù)值3分片將會得到[['a','b','c'], ['d','e']], 如果分片時指定fill_with=' ',結(jié)果將會是[['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,這樣當(dāng)value為 false是將會打印缺省值 這個過濾器的別名是d *'''dictsort(value, case_sensitive=False, by='key')''' 字典排序,,case_sensitive決定是否大小寫敏感,,by決定是按照key排序還是按value排序 *'''escape(s)''' html字符轉(zhuǎn)義,別名是e *'''filesizeformat(value)''' 將一個大數(shù)字轉(zhuǎn)換成KMG形式,,如:1.3k,,34g,25.3m等等 *'''first(seq)''' 返回序列的第一個值 *'''float(value, default=0.0)''' 將一個值轉(zhuǎn)換成浮點數(shù),,如果轉(zhuǎn)換失敗則返回default *'''forceescape(value)''' 不管value是否被轉(zhuǎn)義過,,一律進行html轉(zhuǎn)義。比如value="<", 如果用“value|e|e”則會得到“<",而不是"<",如果用forceescape則會得 到"<" *'''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轉(zhuǎn)換成整數(shù),如果轉(zhuǎn)換失敗則返回default *'''join(seq, d=u”)''' 將序列seq中的各個值用d字符連接起來形成一個字符串,。 *'''last(seq)''' 序列的最后一個值,。 *'''length(object)''' 序列或者字典的長度 別名:count *'''list(value)''' 將value轉(zhuǎn)換為序列,如果value是字符串,,則將字符串轉(zhuǎn)換為字符數(shù)組。 *'''lower(s)''' 將字符串轉(zhuǎn)換為小寫 *'''pprint(value, verbose=False)''' debug時使用,,可以打印變量的詳細信息,。 *'''random(seq)''' 隨機從序列中取得一個值。 *'''replace(s, old, new, count=None)''' 將字符s中的old字符串替換為new字符串,如果給定了count,,則最多替換count次,。 *'''reverse(value)''' 將一個序列反轉(zhuǎn)。 *'''round(value, precision=0, method='common')''' 浮點數(shù)求精,。precision是小數(shù)點位數(shù),,method有common,ceil,floor三種。common是四舍五入,,ceil和floor與 python的同名函數(shù)功能相同,。 *'''safe(value)''' 如果當(dāng)前模板設(shè)置了html自動轉(zhuǎn)義,用此過濾器可以使value不轉(zhuǎn)義 *'''slice(value, slices, fill_with=None)''' 將序列分片,,用fill_with字符填充最后一組子序列長度不足的部分,。 *'''sort(value, reverse=False)''' 將序列按從小到大排序,reverse為true則按從大到小排序 *'''string(object)''' 將一個對象轉(zhuǎn)換為unicode字符串 *'''striptags(value)''' 去掉字符串value中的html,,xml標簽 *'''sum(sequence, start=0)''' 統(tǒng)計數(shù)值序列的和,。start表示從第幾項開始計算 *'''title(s)''' 將字符串s中每個單詞首字符大寫 *'''trim(value)''' 去掉字符串value中首尾的空格 *'''truncate(s, length=255, killwords=False, end='...')''' 截斷一個字符串為length長度,末尾補end字符,。killword為false則將最后一個單詞完整保留,,為True則將嚴格按照給定的長度截斷。 *'''upper(s)''' 將字符串轉(zhuǎn)換為大寫 *'''urlize(value, trim_url_limit=None, nofollow=False)''' *'''wordcount(s)''' 統(tǒng)計字符串中單詞的個數(shù) *'''wordwrap(s, pos=79, hard=False)''' 將字符串s按照pos長度換行,。如果hard為True,,則強制截斷單詞。 *'''xmlattr(d, autospace=True)''' 創(chuàng)建一個sgml/xml的屬性字符串,,例如: <pre> <ul{{ {'class': 'my_list', 'missing': none, 'id': 'list-%d'|format(variable)}|xmlattr }}> ... </ul> </pre> 結(jié)果會是這個樣子: <pre> <ul class="my_list" id="list-42"> ... </ul> </pre> 值會自動進行html轉(zhuǎn)義,,如果為未定義或者None則忽略。 *'''autospace''': 自動在首部添加空格. 內(nèi)建檢查器 *'''callable(object)''' 對象是否可調(diào)用 *'''defined(value)''' 對象是否已定義 *'''divisibleby(value, num)''' value是否可以被num整除 *'''escaped(value)''' 是否已轉(zhuǎn)義 *'''even(value)''' 是否為奇數(shù) *'''iterable(value)''' 是否可以循環(huán) *'''lower(value)''' 是否為小寫 *'''none(value)''' 是否為None *'''number(value)''' 是否為數(shù)字 *'''odd(value)''' 是否為偶數(shù) *'''sameas(value, other)''' value是否與other為同一個對象實例 *'''sequence(value)''' 是否為序列 *'''string(value)''' 是否是字符串 *'''undefined(value)''' 是否未定義 *'''upper(value)''' 是否為大寫
|