Sunday, November 24, 2013

mako二三事 -- 模板载入与encoding

mako是python中比较流行的一个模板引擎,网络上也有很多相关的介绍,因此这个系列文章主要关注mako中一些平常不太注意的内容。


一、字符串直接渲染
mako可以直接对一段字符串进行渲染,不过这没有多少实际意义,直接用用%或字符串拼接即可,基本用于测试演示用途。
from mako.template import Template

mytemplate = Template("hello, ${name}!")
print mytemplate.render(name="jack") 

如果字符串中包含了中文等内容,需要使用unicode类型:
mytemplate = Template(u"你好, ${name}!")
print mytemplate.render(name="jack")  

如果不希望使用unicode类型,则需要指定特定的input_encoding
mytemplate = Template("你好, ${name}!", input_encoding="utf-8")  
print mytemplate.render(name="jack")  
 

二、单模板渲染
mako也可以载入单个模板文件进行渲染,只要指定文件的绝对路径即可
from mako.template import Template

mytemplate = Template(filename='/dir1/a.html')
print mytemplate.render()

如果a.html有特定的编码格式,也需要指定input_encoding
mytemplate = Template(filename='/dir1/a.html', input_encoding="utf-8")
print mytemplate.render() 

Template中还可以指定模板编译之后的中间文件存储路径,可以方便模板语法问题的调试。
mytemplate = Template(filename='/dir1/a.html', input_encoding="utf-8", module_directory='/tmp')
print mytemplate.render() 
注意,mako会在/tmp目录下生成/dir1/a.html.py文件,也就是说会将filename中包含的文件路径在module_directory中生成一遍。

但是如果这个模板中包含了include之类的mako语法,这种载入方式就会因找不到文件而报错。


三、模板lookup
在mako最常用的还是TemplateLookup,为mako指定一个模板文件存放路径,而将模板查找工作交给mako处理。

from mako.template import Template
from mako.lookup import TemplateLookup
mylookup = TemplateLookup(directories=['/dir1','/dir2' ])
mytemplate = mylookup.get_template("a.html")
 
TemplateLookup中,可以指定多个路径,mako按顺序逐个查找,直到找到模板文件。使用了TemplateLookup之后,建议使用get_template函数得到模板。Template类中尽管可以指定lookup参数,但其他参数无法从lookup中取得预先设定的信息,会引起很多错误。
如有一下目录结构:
/dir1
    a.html(模板中include了c.html)
    c.html(模板有中文内容)
/dir2
    b.html

那么
mylookup = TemplateLookup(directories=['/dir1','/dir2’ ], input_encoding="utf-8") 

mytemplate = Template(filename="a.html", lookup=mylookup)       # 提示找不到a.html文件

mytemplate = Template(filename="/dir1/a.html", lookup=mylookup)     # 正确,文件找到
print mytemplate.render()    # 提示找不到模板c.html,lookup没起作用

mytemplate = Template(filename="/dir1/c.html", lookup=mylookup)     # 出错,提示编码出错,也就是说input_encoding没起作用

mytemplate = Template(filename="/dir1/c.html", lookup=mylookup, input_encoding="utf-8")    # 正确
print mytemplate.render()   # 解析正确 

mytemplate = Template(filename="/dir1/b.html", lookup=mylookup)     # 正确,文件找到
print mytemplate.render()   # 解析正确

mytemplate = Template("""<%include file="a.html"/>""", lookup=mylookup)      # 正确,文件找到
print mytemplate.render()   # 解析正确  

mytemplate = Template("""<%include file="b.html"/>""", lookup=mylookup)      # 正确,文件找到
print mytemplate.render()   # 解析正确 

mytemplate = mylookup.get_template("a.html") 
print mytemplate.render()   # 解析正确 
 
mytemplate = mylookup.get_template("b.html") 
print mytemplate.render()   # 解析正确 
 
mytemplate = mylookup.get_template(“c.html")
print mytemplate.render()    # 解析正确 

TemplateLookup也可以指定模板编译之后的中间文件存储路径。 
mytemplate = TemplateLookup(directories=['/dir1','/dir2’ ], input_encoding="utf-8", module_directory='/tmp')
mytemplate = mylookup.get_template(“c.html") 
print mytemplate.render() 
其文件路径也是module_directory + get_template中指定的相对路径。

四、encoding
除了input_encoding之外,mako需要关注的output_encoding。在不指定输出编码时,render()输出unicode字符串。

>>> mylookup = TemplateLookup(directories=['/dir1','/dir2' ], input_encoding="utf-8") 
>>> mytemplate = mylookup.get_template("c.html")
>>> mytemplate.render()
u'\u4e2d\u6587\n'

输出utf-8
>>> mylookup = TemplateLookup(directories=['/dir1','/dir2' ], input_encoding="utf-8", output_encoding="utf-8")
>>> mytemplate = mylookup.get_template("c.html")
>>> mytemplate.render() 
'\xe4\xb8\xad\xe6\x96\x87\n' 

输出gbk
>>> mylookup = TemplateLookup(directories=['/dir1','/dir2' ], input_encoding="utf-8", output_encoding="gbk") 
>>> mytemplate = mylookup.get_template("c.html")
>>> mytemplate.render()
'\xd6\xd0\xce\xc4\n’

 如果使用了render_unicode()函数输出,则output_encoding 参数被忽略
>>> mylookup = TemplateLookup(directories=['/dir1','/dir2' ], input_encoding="utf-8", output_encoding="utf-8")>>> mytemplate = mylookup.get_template("c.html")
>>> mytemplate.render_unicode()
u'\u4e2d\u6587\n' 

注:系统环境
OS: OS X 10.9
Python: 2.7.5

No comments:

Post a Comment