Mako 模板

Mako 是Python语言的一个模板处理库.

它能提供编译为常见的非XML语法的高性能的Python模块.

Mako 的语法及API融合了很多模块系统的亮点, 如常用的 Django, Cheetah, Myghty, Genshi等等.

从概念上讲, Mako 属于一种内嵌Python语言(如Python的服务端页面). 这样模板开发者精确的想法布局实现及简单而直接地继承. 模式灵活同时还保证了与应用与Python的调用及语义的紧密联系.

<%inherit file="base.html"/>
<%
    rows = [[v for v in range(0,10)] for row in range(0,10)]
%>

<table>
    % for row in rows:
        ${makerow(row)}
    % endfor
</table>

<%def name="makerow(row)">
    <tr>
    % for name in row:
        <td>${name}</td>
    % endfor
    </tr>
</%def>

功能

API简洁, 最简单的例子, 只需要引用一个 Template class 即可.

from mako.template import Template
print Template("hello ${data}!").render(data="world")

另一个例子,使用文件模板以及模板缓存,模板文件优先查询的处理.

Insanely Fast. An included bench suite, adapted from a suite included with Genshi, has these results for a simple three-sectioned layout:

Mako: 1.10 ms                                             Kid: 14.54 ms
  • 标准模板功能
    • 模板结构,逻辑控制使用标准Python语法(如 循环语句, 条件语句等)
    • straight Python blocks, inline or at the module-level
  • 可重复使用模板块
    • can access variables from their enclosing scope as well as the template’s request context
    • 模块任意嵌套
    • can specify regular Python argument signatures
    • outer-level callable blocks can be called by other templates or controller code (i.e. “method call”)
    • calls to functions can define any number of sub-blocks of content which are accessible to the called function (i.e. “component-call-with-content”). This is the basis for nestable custom tags.
  • 模板继承
    • supports “multi-zoned” inheritance - define any number of areas in the base template to be overridden.
    • supports “chaining” style inheritance - call next.body() to call the “inner” content.
    • the full inheritance hierarchy is navigable in both directions (i.e. parent and child) from anywhere in the chain.
    • inheritance is dynamic ! Specify a function instead of a filename to calculate inheritance on the fly for every request.

例子

  • 基本用法
from mako.template import Template

mytemplate = Template("hello world!")
print mytemplate.render()

传给 Template 的模板文本被处理成一种类似 Python 模块的对象.

这个模块对象有一个 render_body() 方法, 用于将模板处理为最终的输出结果.

当 mytemplate.render() 时,Mako 会处理当前的运行环境并调用 render_body() 方法渲染模板后返回处理结果为一个 字符串.

The code inside the render_body() function has access to a namespace of variables. You can specify these variables by sending them as additional keyword arguments to the render() method:

from mako.template import Template

mytemplate = Template("hello, ${name}!")
print mytemplate.render(name="openerp")
  • 基于文件的模板

使用文件做为模板代码源, 只需要使用 filename 参数指定文件路径即可:

from mako.template import Template

mytemplate = Template(filename='/test.html')
print mytemplate.render()
  • 使用 TemplateLookup 匹配最佳模板

到目前, 所有的例子还都是只使用单一的 Template 模板.

如果模板代码中引用一个本地的另一个模板资源, Mako 则可以使用简单的 URI 串来指定查找位置.

因此, TemplateLookup 类就解决了在一个模板中引用其它模板的问题.

该类将按给定的目录列表查找模板, This class is constructed given a list of directories in which to search for templates, as well as keyword arguments that will be passed to the Template objects it creates:

from mako.template import Template
from mako.lookup import TemplateLookup

mylookup = TemplateLookup(directories=[''])
mytemplate = Tempalte('<% include file="header.txt"/> Hello!',lookup=mylookup)

上面的代码, 则创建了一个引用了 “header.txt” 文件的模板.

为了让系统能找到 “header.txt” 模板, 我们传了一个 TemplateLookup 对象过去,告诉系统从当前文件夹中查找 “header.txt”.

语法

  • 表达式

模板最简单的表达式就是模板变量的替换了.

${} 的语法类似于 Perl, Genshi, JSP EL等模板系统的语法:

${x}
${5%5}
${7*2}
${pow(x,2) + pow(y,2)}
  • 流程控制
    • 条件语句(如: if/else)
    • 循环语句(如: for 与 while)
    • 异常控制(如: try/except)

模板的流程控制完全使用 Python 语言的流程控制语法, 只不过, 在模板流程控制结束, 需要使用 “%end<name>”来做为控制结束符. 其中 “<name>” 为控制语句的 Python 保留字. 例如:

% if user_name == 'openerp':
    valid user
% endif

% if a > 1:
    a is positive number
% elif a == 0:
    a is 0
% else:
    a is negative number
% endif

<table>
% for a in [1,2,3,4,5]:
    <tr>
        <td>
            ${a}
        </td>
    </tr>
% endfor
</table>
  • Python 代码块

你可以在模板的 <% %> 标符内随意使用 Python 代码:

<%
    a = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
    b = a.values()
%>
% for x in b:
    ${x}
% endfor
  • Module-level Blocks

<% %> Python 代码块的另一种方式是可以使用 <%! %> 做为定界符.

模板里这个标签内的代码可以执行, 但是函数定义里的代码并不立即执行.

<%!
    import cherrypy
    def get_user_from_session():
        return cherrypy.session['current_user']
%>

Therefore, this code does not have access to the template’s context and is only executed when the template is loaded into memory (which can be only once per application, or more, depending on the runtime environment).

  • Mako Tags

<%page>

<%page> 标签是在模板中常用的标签, 在标签内可以配置页面的缓存参数,以及模板引用时需要的一些可选择的列表.

Also defines caching characteristics.

<%page args="x, y, z='default'"/>
<%page cached="True" cache_type="memory"/>

<%include>

只需要传递一个参数就可以调用该参数对应的模板.

Also accepts arguments which are available as <%page> arguments in the receiving template:

<%include file="header.mako"/>
    Welcome to OpenERP
<%include file="footer.mako"/>

<%include file="toolbar.html" args="current_section='members', username='ed'"/>

<%inherit>

Inherit allows templates to arrange themselves in inheritance chains.

When using the %inherit tag, control is passed to the topmost inherited template first, which then decides how to handle calling areas of content from its inheriting templates.

<%inherit file="index.mako"/>

<%def>

The %def tag defines a Python function which contains a set of content, that can be called at some other point in the template.

The %def tag is a lot more powerful than a plain Python def, as the Mako compiler provides many extra services with %def that you wouldn’t normally have, such as the ability to export defs as template “methods”, automatic propagation of the current Context, buffering/filtering/caching flags, and def calls with content, which enable packages of defs to be sent as arguments to other def calls (not as hard as it sounds).

<%def name="my_function(x)">
    this is function ${x}
<%def>

<%namespace>

%namespace is Mako’s equivalent of Python’s import statement.

这允许访问所有的渲染函数及其它模板文件的元数据, plain Python modules, 甚至本地定义的函数包.

<%namespace file="test.mako" import="*"/>

<%doc>

处理多行内容:

<%doc>
    多行内容
    使用文档标签
</%doc>

更多的资料,请访问访官方文档: http://www.makotemplates.org/docs/index.html