Python模板庫Mako的用法

Mako是一個高性能的Python模板庫,它的語法和API借鑑了不少其餘的模板庫,如Django、Jinja2等等。css

基本用法

建立模板並渲染它的最基本的方法是使用 Template 類:html

from mako.template import Template
t = Template('hello world!')
print t.render()

傳給 Template 的文本參數被編譯爲一個Python模塊。模塊包含一個 render_body() 函數,它產生模板的輸出。調用 render() 方法時,Mako創建了一個模板的運行環境,並調用 render_body() 函數,把輸出保存到緩衝,返回它的字符串內容。
render_body() 函數中能夠訪問一個變量集。能夠向 render() 方法發送額外的關鍵詞參數來指定這些變量:python

from mako.template import Template
t = Template('hello, ${name}!')
print t.render(name='yeolar')

render() 方法使Mako建立一個 Context 對象,它存儲模板能夠訪問的全部變量和一個用來保存輸出的緩衝。也能夠本身建立 Context ,用 render_context() 方法使模板用它來渲染:web

from mako.template import Template
from mako.runtime import Context
from StringIO import StringIO
t = Template('hello, ${name}!')
buf = StringIO()
c = Context(buf, name='yeolar')
t.render_context(c)
print buf.getValue()

使用文件模板

Template 也能夠從文件加載模板,使用 filename 參數:django

from mako.template import Template
t = Template(filename='/docs/tpl.txt')
print t.render()

爲了提升性能,從文件加載的 Template 還能夠在文件系統中將生成的模塊緩存爲通常的Python模塊文件(.py文件),這經過添加 module_directory 參數實現:緩存

from mako.template import Template
t = Template(filename='/docs/tpl.txt', module_directory='/tmp/mako_modules')
print t.render()

上面的代碼渲染後,會建立一個/tmp/mako_modules/docs/tpl.txt.py文件,其中包含模塊的源代碼。下次一樣參數的 Template 建立時,自動重用這個模塊文件。app

使用TemplateLookup

到如今的例子都是有關單個 Template 對象的用法。若是模板中的代碼要定位其餘模板資源,須要某種使用URI來找到它們的方法。這種需求是由 TemplateLookup 類來達到的。這個類經過傳入一個模板查找目錄的列表來構造,而後做爲關鍵詞參數傳給 Template 對象:ide

from mako.template import Template
from mako.lookup import TemplateLookup
lookup = TemplateLookup(directories=['/docs'])
t = Template('<%include file="header.txt" /> hello word!', lookup=lookup)

上面建立的模板中包含文件header.txt。爲了查找header.txt,傳了一個 TemplateLookup 對象給它。
一般,應用會以文本文件形式在文件系統上存儲大部分或所有的模板。一個真正的應用會直接從 TemplateLookup 取得它的模板,使用 get_template() 方法,它接受須要的模板的URI做爲參數:函數

from mako.template import Template
from mako.lookup import TemplateLookup
lookup = TemplateLookup(directories=['/docs'], module_directory='/tmp/mako_modules')
def serve_template(t_name, **kwargs):
    t = lookup.get_template(t_name)
    print t.render(**kwargs)

上面的例子中咱們建立了一個 TemplateLookup ,它從/docs目錄中查找模板,並把全部的模塊文件存儲到/tmp/mako_modules目錄中。經過將傳入的URI附加到每一個查找目錄來定位模板,如傳遞/etc/beans/info.txt,將查找文件/docs/etc/beans/info.txt,若是沒找到將拋出 TopLevelNotFound 異常。
當定位到模板的時候,傳給 get_template() 調用的URI也會做爲 Template 的 uri 屬性。 Template 使用這個URI來獲得模塊文件的名字,所以上面的例子中對/etc/beans/info.txt會建立模塊文件/tmp/mako_modules/etc/beans/info.txt.py。tornado

設置收集的大小

TemplateLookup 還知足將內存中緩存的模板總數設爲一個固定的值。默認狀況 TemplateLookup 大小是不限的。能夠用 collection_size 參數指定一個固定值:

lookup = TemplateLookup(directories=['/docs'], module_directory='/tmp/mako_modules', collection_size=500)

上面的 lookup 將模板加載到內存中的上限是500個。以後,它將使用LRU策略來清理替換模板。

設置文件系統檢查

TemplateLookup 的另外一個重要標誌是 filesystem_checks 。默認爲 True ,每次 get_template() 方法返回一個模板,會比較原始模板文件的修改時間和模板的最近加載時間,若是文件更新,就從新加載和編譯模板。在生產系統中,將 filesystem_checks 設爲 False 能得到一些性能的提高。

使用Unicode和編碼

Template 和 TemplateLookup 能夠設置 output_encoding 和 encoding_errors 參數來將輸出編碼爲Python支持的編碼格式:

from mako.template import Template
from mako.lookup import TemplateLookup
lookup = TemplateLookup(directories=['/docs'], output_encoding='utf-8', encoding_errors='replace')
t = lookup.get_template('foo.txt')
print t.render()

使用Python 3時,若是設置了 output_encoding , render() 方法將返回一個 bytes 對象,不然返回 string 。
render_unicode() 方法返回模板輸出爲Python unicode 對象,Python 3爲 string :

print t.render_unicode()

上面的方法沒有輸出編碼的參數,能夠自行編碼:

print t.render_unicode().encode('utf-8', 'replace')

注意Mako中模板的底層輸出流是Python Unicode對象。

處理異常

模板異常可能發生在兩個地方。一個是當你查找、解析和編譯模板的時候,一個是運行模板的時候。模板運行中發生的異常會正常在產生問題的Python代碼處拋出。Mako有本身的一組異常類,它們主要用於模板構造的查找和編譯階段。Mako提供了一些庫例程用來對異常棧提供Mako的信息,並將異常輸出爲文本或HTML格式。Python文件名、行號和代碼片斷會被轉換爲Mako模板文件名、行號和代碼片斷。Mako模板模塊的行會被轉換爲原始的模板文件對應行。

text_error_template() 和 html_error_template() 函數用於格式化異常跟蹤。它們使用 sys.exc_info() 來獲得最近拋出的異常。這些處理器的用法像下面這樣:

from mako import exceptions
try:
    t = lookup.get_template(uri)
    print t.render()
except:
    print exceptions.text_error_template().render()
或者渲染爲HTML:
from mako import exceptions
try:
    t = lookup.get_template(uri)
    print t.render()
except:
    print exceptions.html_error_template().render()

html_error_template() 模板接受兩個選項:指定 full=False 只渲染HTML的一節,指定 css=False 關閉默認的樣式表。如:

print exceptions.html_error_template().render(full=False)

HTML渲染函數也能夠用 format_exceptions 標誌加到 Template 中。這種狀況下,模板在渲染階段的任何異常在輸出中的結果都會替換爲 html_error_template() 的輸出:

t = Template(filename='/foo/bar', format_exceptions=True)
print t.render()

注意上面模板的編譯階段發生在構造 Template 時,沒有定義輸出流。所以查找、解析、編譯階段發生的異常正常狀況下不會被處理,而是傳播下去。渲染前的追溯不包括Mako形式的行,這意味着渲染前和渲染中發生的異常會用不一樣的方式處理,所以 try/except 可能更經常使用。

錯誤模板函數使用的底層對象是 RichTraceback 對象。這個對象也能夠直接用來提供自定義的錯誤視圖。下面是一個用法的樣例:

from mako.exceptions import RichTraceback
try:
    t = lookup.get_template(uri)
    print t.render()
except:
    traceback = RichTraceback()
    for (filename, lineno, function, line) in traceback.traceback:
        print 'File %s, line %s, in %s' % (filename, lineno, function)
        print line, '\n'
    print '%s: %s' % (str(traceback.error.__class__.__name__), traceback.error)

集成Mako

在Django中集成Mako

經過Django的中間件能夠集成Mako。首先須要安裝django-mako模塊。
在Django項目的settings.py文件中,修改 MIDDLEWARE_CLASSES ,添加 djangomako.middleware.MakoMiddleware 。使用 render_to_response() 函數便可使用:

from djangomako.shortcuts import render_to_response
def hello_view(request):
    return render_to_response('hello.txt', {'name': 'yeolar'})

在Tornado中集成Mako

在Tornado中能夠直接使用Mako,下面是一個使用示例:

 
import tornado.web
import mako.lookup
import mako.template
LOOK_UP = mako.lookup.TemplateLookup(
        directories=[TEMPLATE_PATH], module_directory='/tmp/mako',
        output_encoding='utf-8', encoding_errors='replace')
class BaseHandler(tornado.web.RequestHandler):
    def initialize(self, lookup=LOOK_UP):
        '''Set template lookup object, Defalut is LOOK_UP'''
        self._lookup = lookup
    def render_string(self, filename, **kwargs):
        '''Override render_string to use mako template.
        Like tornado render_string method, this method
        also pass request handler environment to template engine.
        '''
        try:
            template = self._lookup.get_template(filename)
            env_kwargs = dict(
                handler = self,
                request = self.request,
                current_user = self.current_user,
                locale = self.locale,
                _ = self.locale.translate,
                static_url = self.static_url,
                xsrf_form_html = self.xsrf_form_html,
                reverse_url = self.application.reverse_url,
                )
            env_kwargs.update(kwargs)
            return template.render(**env_kwargs)
        except:
            # exception handler
            pass
    def render(self, filename, **kwargs):
        self.finish(self.render_string(filename, **kwargs))
相關文章
相關標籤/搜索