在Python中使用Mako模版库的简单教程


Posted in Python onApril 08, 2015

Mako是一个高性能的Python模板库,它的语法和API借鉴了很多其他的模板库,如Django、Jinja2等等。
基本用法

创建模板并渲染它的最基本的方法是使用 Template 类:
 

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

传给 Template 的文本参数被编译为一个Python模块。模块包含一个 render_body() 函数,它产生模板的输出。调用 render() 方法时,Mako建立了一个模板的运行环境,并调用 render_body() 函数,把输出保存到缓冲,返回它的字符串内容。
render_body() 函数中可以访问一个变量集。可以向 render() 方法发送额外的关键词参数来指定这些变量:
 

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

render() 方法使Mako创建一个 Context 对象,它存储模板可以访问的所有变量和一个用来保存输出的缓冲。也可以自己创建 Context ,用 render_context() 方法使模板用它来渲染:
 

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 参数:
 

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 创建时,自动重用这个模块文件。
使用TemplateLookup

到现在的例子都是有关单个 Template 对象的用法。如果模板中的代码要定位其他模板资源,需要某种使用URI来找到它们的方法。这种需求是由 TemplateLookup 类来达到的。这个类通过传入一个模板查找目录的列表来构造,然后作为关键词参数传给 Template 对象:
 

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。
设置收集的大小

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))
Python 相关文章推荐
python备份文件的脚本
Aug 11 Python
python PyTorch参数初始化和Finetune
Feb 11 Python
pandas DataFrame实现几列数据合并成为新的一列方法
Jun 08 Python
python的常用模块之collections模块详解
Dec 06 Python
python2.7 安装pip的方法步骤(管用)
May 05 Python
python实现翻转棋游戏(othello)
Jul 29 Python
python实现ip地址查询经纬度定位详解
Aug 30 Python
Django1.11自带分页器paginator的使用方法
Oct 31 Python
Python socket聊天脚本代码实例
Jan 02 Python
selenium设置浏览器为headless无头模式(Chrome和Firefox)
Jan 08 Python
利用Matlab绘制各类特殊图形的实例代码
Jul 16 Python
Python如何加载模型并查看网络
Jul 15 Python
python中requests模块的使用方法
Apr 08 #Python
介绍Python中几个常用的类方法
Apr 08 #Python
python自然语言编码转换模块codecs介绍
Apr 08 #Python
python文件写入实例分析
Apr 08 #Python
python uuid模块使用实例
Apr 08 #Python
Python HTMLParser模块解析html获取url实例
Apr 08 #Python
python内存管理分析
Apr 08 #Python
You might like
第八节--访问方式
2006/11/16 PHP
利用PHP实现智能文件类型检测的实现代码
2011/08/02 PHP
php 操作调试的方法
2012/07/12 PHP
php中判断数组是一维,二维,还是多维的解决方法
2013/05/04 PHP
php实现查询百度google收录情况(示例代码)
2013/08/02 PHP
php采用file_get_contents代替使用curl实例
2014/11/07 PHP
php获取一定范围内取N个不重复的随机数
2016/05/28 PHP
PHP中FTP相关函数小结
2016/07/15 PHP
JavaScript延迟加载
2021/03/09 Javascript
使用Json比用string返回数据更友好,也更面向对象一些
2011/09/13 Javascript
5分钟理解JavaScript中this用法分享
2013/11/09 Javascript
js中window.open()的所有参数详细解析
2014/01/09 Javascript
javascript使用for循环批量注册的事件不能正确获取索引值的解决方法
2014/12/20 Javascript
Javascript中arguments和arguments.callee的区别浅析
2015/04/24 Javascript
jQuery禁用键盘后退屏蔽F5刷新及禁用右键单击
2016/01/22 Javascript
Vue2.x中的父子组件相互通信的实现方法
2017/05/02 Javascript
详解微信小程序scroll-view横向滚动的实践踩坑及隐藏其滚动条的实现
2019/03/14 Javascript
Vue如何跨组件传递Slot的实现
2020/12/14 Vue.js
[30:37]【全国守擂赛】第三周擂主赛 Dark Knight vs. Leopard Gaming
2020/05/04 DOTA
Python实现 PS 图像调整中的亮度调整
2019/06/28 Python
在Python中构建增广矩阵的实现方法
2019/07/01 Python
python之拟合的实现
2019/07/19 Python
python科学计算之scipy——optimize用法
2019/11/25 Python
Sephora丝芙兰澳洲官方网站:国际知名化妆品购物
2016/10/27 全球购物
马来西亚和新加坡巴士票在线预订:CatchThatBus
2018/11/17 全球购物
斯巴达比赛商店:Spartan Race
2019/01/08 全球购物
飞利浦西班牙官方网站:Philips西班牙
2020/02/17 全球购物
香港百佳网上超级市场:PARKNSHOP.com
2020/06/10 全球购物
了解AppleTalk协议吗
2014/04/01 面试题
shell变量的作用空间是什么
2013/08/17 面试题
本科生自荐信
2014/06/18 职场文书
骨干教师考核评语
2014/12/31 职场文书
英文道歉信
2015/01/20 职场文书
mysql在项目中怎么选事务隔离级别
2021/05/25 MySQL
国产动画《万圣街》日语配音版制作决定!
2022/03/20 国漫
Go Grpc Gateway兼容HTTP协议文档自动生成网关
2022/06/16 Golang