Mako 模板系统.docx

上传人:b****5 文档编号:7364180 上传时间:2023-01-23 格式:DOCX 页数:42 大小:51.65KB
下载 相关 举报
Mako 模板系统.docx_第1页
第1页 / 共42页
Mako 模板系统.docx_第2页
第2页 / 共42页
Mako 模板系统.docx_第3页
第3页 / 共42页
Mako 模板系统.docx_第4页
第4页 / 共42页
Mako 模板系统.docx_第5页
第5页 / 共42页
点击查看更多>>
下载资源
资源描述

Mako 模板系统.docx

《Mako 模板系统.docx》由会员分享,可在线阅读,更多相关《Mako 模板系统.docx(42页珍藏版)》请在冰豆网上搜索。

Mako 模板系统.docx

Mako模板系统

Mako模板系统文档

一、使用基础

这一节介绍Makotemplate的 PythonAPI.如果你在Pylons之类的web框架中使用Mako,那么集成MakoAPI的工作也许已经给你做好了。

你可以直接跳到下一节,语法。

最简单的办法是通过Template类,创建模板并渲染之:

frommako.templateimportTemplate

mytemplate=Template("helloworld!

")

printmytemplate.render()

上述例子中,传递给Template的文本参数被编译成了一个python的模块。

该模块有一个render_body()函数,用于输出模板内容。

当mytemplate.render()被调用时,Mako会为此模板创建起一个运行时环境,并调用render_body()函数,然后捕获其输出到缓冲区,然后返回其字符串内容。

render_body()函数中的代码可以访问包含了一些变量的一个名称空间。

你可以传递额外的关键字参数给render()方法,这些参数将转化为可被访问的变量:

frommako.templateimportTemplate

mytemplate=Template("hello,${name}!

")

printmytemplate.render(name="jack")

template.render()方法会让Mako创建一个Context对象,其中包含了所有该模板可访问的变量的名称,以及一个用于捕获输出的缓冲区。

你也可以自己创建Context对象,并命令模板利用此Context来render,用render_context方法即可:

frommako.templateimportTemplate

frommako.runtimeimportContext

fromStringIOimportStringIO

mytemplate=Template("hello,${name}!

")

buf=StringIO()

ctx=Context(buf,name="jack")

mytemplate.render_context(ctx)

printbuf.getvalue()

1使用基于文件的模板

你也可以从文件中加载Template的内容,使用filename关键字参数:

 

frommako.templateimportTemplate

mytemplate=Template(filename='/docs/mytmpl.txt')

printmytemplate.render()

为提高性能,从文件中加载的Template,可以将它产生的模块的源代码以普通python模块文件的形式(.py),缓存到文件系统中。

只要加一个参数module_directory即可做到这一点:

frommako.templateimportTemplate

mytemplate=Template(filename='/docs/mytmpl.txt',module_directory='/tmp/mako_modules')

printmytemplate.render()

当上述代码被render的时候,会创建文件 /tmp/mako_modules/docs/mytmpl.txt.py.下一次Template对象被用同样参数调用的时候,就会直接重用该模块文件。

2使用TemplateLookup

在模板中,我们有时候需要调用或引用其他模板的内容,这就牵涉一个模板查找定位的问题,通常用简单的URI字符串来定位。

我们用TemplateLookup 类来负责这个任务。

该类的构造函数需要传递一系列可供查找模板的路径的列表。

然后我们再将此TemplateLookup对象用关键字参数的形式传递给Template对象。

frommako.templateimportTemplate

frommako.lookupimportTemplateLookup

mylookup=TemplateLookup(directories=['/docs'])

mytemplate=Template("""<%includefile="header.txt"/>helloworld!

""",

   lookup=mylookup)

上述例子中创建了一个文本模板,其中有一个对header.txt文件的包含引用。

而从何处去查找header.txt,则由TemplateLookup指明,是"/docs"目录。

通常,应用程序会把模板用文本文件的形式保存在文件系统中。

而为了方便起见,我们可以直接通过TemplateLookup来获取模板对象,利用TemplateLookup的get_template方法,并传递模板的URI作为参数:

frommako.templateimportTemplate

frommako.lookupimportTemplateLookup

mylookup=TemplateLookup(directories=['/docs'],module_directory='/tmp/mako_modules')

defserve_template(templatename,**kwargs):

mytemplate=mylookup.get_template(templatename)

printmytemplate.render(**kwargs)

lookup在查找模板时通过向其中的每一个搜索路径附加我们提供的模板URI的方式,来尝试获取模板文件。

如果找不到则引发TopLevelNotFound异常,这是一个Mako的自定义异常类型。

当lookup找到模板时,它还会给Template指定一个uri属性,这个uri就是传递给get_template()方法的参数。

Template可以用此uri来计算出其对应的模块文件的名称。

比如在上述例子中,/etc/beans/info.txt这个URI名称参数,会导致创建模块文件/tmp/mako_modules/etc/beans/info.txt.py.

3设定集合的大小

TemplateLookup同时也会在内存中缓存一组模板,所以并不是每一次请求都会导致模板的重新编译和模块重新加载。

默认TemplateLookup的大小没有限制,但你可以通过collection_size参数来限制它:

mylookup=TemplateLookup(directories=['/docs'],

module_directory='/tmp/mako_modules',collection_size=500)

以上的lookup会持续加载模板到内存中,直到达到500的时候,它就会清除掉一定比例的模板缓存项,根据“最近最少访问”原则。

4设置文件系统检查

另一个TemplateLookup相关的标志是  filesystem_checks.默认为True,每一次get_template()方法返回模板后,原始的模板文件的revisiontime会和上次加载模板的时间做对比,如果文件更新,则会加载其内容,并重新编译该模板。

在生产环境下,设置filesystem_checks为False可以带来一定的性能提升(和具体的文件系统有关)。

5使用Unicode和Encoding

Template 和 TemplateLookup 都可以接受 output_encoding 和 encoding_errors 参数,用来对输出以Python支持的任何方式进行编码:

frommako.templateimportTemplate

frommako.lookupimportTemplateLookup

mylookup=TemplateLookup(directories=['/docs'],output_encoding='utf-8',

encoding_errors='replace')

mytemplate=mylookup.get_template("foo.txt")

printmytemplate.render()

另外,render_unicode()方法可以将模板的输出转换为一个Python的Unicode对象返回:

printmytemplate.render_unicode()

上面的方法调用未提供输出编码参数,你可以通过下列语法来进行编码:

printmytemplate.render_unicode().encode('utf-8','replace')

注意,Mako能将数据返回为任何encoding或unicode的能力暗示着,模板内部的输出流是一个Pythonunicode对象。

这种行为的详细描述在 TheUnicodeChapter.

6处理异常

模板异常可能在两种截然不同的地方出现。

第一种是当你查找,分析和编译模板时,另一种是当你运行模板的时候。

在模板的运行过程中,异常通常从产生问题的python代码出抛出。

Mako有其独立的一套异常类,它们大多数针对模板构造过程的查找和词法分析/编译阶段。

Mako还提供了一些库函数,这些函数用来帮助提供Mako相关的异常栈跟踪信息,并可用纯文本或HTML方式格式化异常信息。

不管是哪种情况,这些处理函数的作用在于将Python文件名,行号,以及代码例子转换为Mako的模板文件名,行号,以及代码范例。

在跟踪栈里对应于某个Moko模板的每一行,都回被转换为和源模板文件相关的。

为了格式化异常跟踪信息,系统提供了text_error_template和html_error_template函数。

它们都利用了sys.exc_info()函数来获取最近抛出的异常信息。

下面是常见的用法:

frommakoimportexceptions

try:

template=lookup.get_template(uri)

printtemplate.render()

except:

printexceptions.text_error_template().render()

如果使用HTML的输出函数:

frommakoimportexceptions

try:

template=lookup.get_template(uri)

printtemplate.render()

except:

printexceptions.html_error_template().render()

HTML输出函数也内建到了Template中。

通过format_exceptions这个标志位参数。

这样,任何在template的render阶段引发的异常,都会使得template的输出内容被html_error_template方法的输出所替代。

template=Template(filename="/foo/bar",format_exceptions=True)

printtemplate.render()

注意,上述模板的编译阶段发生在你构造Template对象本身的时候,并且没有定义输出流。

所以,在查找/解析/编译阶段引发的异常不会被处理,而是像平常那样被继续抛出到更高层次的调用堆栈上(繁殖,propagate)。

虽然pre-rendertraceback不会包含任何Mako特定的行,这意味着发生在rendering之前的异常,以及rendering过程中发生的异常,需要用不同的办法分别处理。

因此,上面的try/except模式可能是比较通用的一种写法。

被错误模板函数使用的内部对象是RichTraceback.该对象也可以被直接用于提供自定义错误视图。

下面是一个范例应用,可以描述其一般使用的API:

frommako.exceptionsimportRichTraceback

try:

template=lookup.get_template(uri)

printtemplate.render()

except:

traceback=RichTraceback()

for(filename,lineno,function,line)intraceback.traceback:

print"File%s,line%s,in%s"%(filename,lineno,function)

printline,"\n"

print"%s:

%s"%(str(traceback.error.__class__.__name__),traceback.error)

关于 RichTraceback 的更深入信息可以查阅mako.exceptions的模块级文档。

二、语法

Mako模板是从文本流中进行解析的,流中可以包含任意内容:

XML,HTML,email文本,等等。

模板中可以包含Mako特定的指令(directives),可用于表示变量或表达式替换,控制结构(如条件和循环),服务器端注释,整段的Python代码,以及各种用于提供附加功能的标签(tags)。

所有这些将被编译为真实的Python代码。

这意味着你可以在Mako模板中利用Python几乎所有的强大特性。

1表达式替换

最简单的表达式是变量替换。

其语法是${},受Perl,Genshi,JSPEL和其他一些语言的启发:

thisisx:

${x}

以上代码中,x的字符串表示形式将被应用到模板的输出流中。

x的值通常来源于你提供给模板rendering函数作为参数的Context变量。

如果x的值未指定给模板,并且也未指定为局部变量,则会估算为一个特殊的值UNDEFINED.

${}中的内容会被Python直接估算,所以各种表达式都是支持的:

pythagoreantheorem:

${pow(x,2)+pow(y,2)}

在render到输出流之前,表达式的结果总是被估算为一个字符串。

2表达式转义(escaping)

Mako包含了一系列内建的转义机制,包括HTML,URI和XML转义,以及"trim"函数。

转义的动作可以通过|运算符附加到表达式后面:

${"thisissometext"|u}

上例中对表达式进行了URL转义,其结果是:

this+is+some+text.其中u代表URL转义,与之类似的,h代表HTML转义,x代表XML转义,而trim则是通常的trim函数。

可以在 FilteringandBuffering 中获取更多关于过滤器函数的内容,包括如何创建你自己的过滤器。

3控制结构

控制结构指的是控制程序流程的那些语法—条件(如if/else),循环(如while和for),以及try/except之类。

在Mako中,控制结构用%后附加常规Python控制结构的写法,并用另一个%语法"end"结束语句块。

其中""是该表达式的关键字:

%ifx==5:

thisissomeoutput

%endif

%可以出现在一行里的任何位置,只要其前面没有其他文本;缩进是无所谓的。

Python中的所有“冒号”表达式在这里都完全支持,包括if/elif/else,while,for甚至def,尽管Mako有其内建的功能更强大的def标签。

%forain['one','two','three','four','five']:

%ifa[0]=='t':

itstwoorthree

%elifa[0]=='f':

four/five

%else:

one

%endif

%endfor

4注释

注释有两种形式。

单行注释在一行中以##开头(前面可以有空白):

##这是一个注释.

...text...

而多行注释则使用<%doc>...文本..的语法:

<%doc>

这里是注释

更多注释

注意,这是Mako0.1.3的新特性。

在此之前的版本中,注释的语法是单个#符号,而这和CSS的元素指示语法冲突,并且不能很好的处理多行注释。

5换行过滤器(NewlineFilters)

反斜线("\")字符放在任意一行的后面,会吃掉一个换行符。

hereisalinethatgoesonto\

anotherline.

上述语法会产生下列文本:

hereisalinethatgoesontoanotherline.

6Python语句块

任意python语句块都可以用<%%>标签来定义:

thisisatemplate

<%

x=db.get_resource('foo')

y=[z.elementforzinxifx.frobnizzle==5]

%>

%foreleminy:

element:

${y}

%endfor

在<%%>内定义的python代码,其整体的缩进量是不重要的,但是他们内部的语句之间必须有正确的缩进层次(因为这里没法使用end),Mako的编译器会调整python语句块的缩进层次与其周围的其他生成的Python代码相配合。

7模块级的语句块

<%%>的一个变体是<%!

%>,代表模块级别的代码块。

其中的代码会在模板的模块级别执行,而不是在模板的rendering函数中。

所以,这段代码不能访问模板的context,仅在模板被加载到内存时被执行(有可能是相对于每应用程序仅执行一次,或者多次,这取决于运行时环境)。

可以使用<%!

%>来定义模板的导入语句:

<%!

importmylib

importre

deffilter(text):

returnre.sub(r'^@','',text)

%>

在模板中,可以在任何位置,定义任意数目的<%!

%>语句块;他们在编译产生的模块文件中出现的次序和定义时相同。

8标签

Mako还提供了标签。

所有标签的语法都一样,类似于XML标签,不同之处在于其标签名称必须以%开头。

标签的关闭可以用反斜杠的内联形式,或者独立的关闭标签:

<%includefile="foo.txt"/>

<%defname="foo"buffered="True">

thisisadef

每种标签都定义了一系列特定的属性。

有些属性是必须的。

并且,很多属性支持估算操作(evaluation),也就是说你可以在属性文本中嵌入一个表达式(用${}语法)。

<%includefile="/foo/bar/${myfile}.txt"/>

属性是否支持运行时的估算,取决于标签的类型,以及该标签是如何编译成模板的。

想知道某个标签的属性是否支持估算,最好的办法就是去试验它!

如果不合法,词法器会告诉你。

下面是所有标签的一个简单介绍:

1<%page>

定义了当前模板的总体特性,包括缓存参数,以及模板被调用时期待的参数列表(非必须)。

<%pageargs="x,y,z='default'"/>

定义缓存特性:

<%pagecached="True"cache_type="memory"/>

关于<%page>使用的细节在 The"body()"method 和 Caching 中有深入描述。

目前只有<%page>标签是模板唯一的,其他的会被胡略,这在将来的发布版本中也许会被改变,但现在请确认这一点。

2<%include>

类似于其他模板语言的一个标签,%include接受一个文件名称作为参数,调用被引用文件的输出结果。

<%includefile="header.html"/>

helloworld

<%includefile="footer.html"/>

3<%def>

%def标签用于定义包含一系列内容的一个Python函数,此函数在当前模板的其他某个地方被调用到:

<%defname="myfunc(x)">

thisismyfunc,xis${x}

${myfunc(7)}

%def标签比Python的def要强大一些,因为Mako的编译器为%def提供了很多额外服务,比如可以导出defs为模板“方法”,自动传播当前的context(原文:

automaticpropigationofthecurrentContext),缓冲/过滤/缓存标志位,以及带有内容的def调用,这使得defs的包可以被以参数的形式,提供给其他的def调用(不像听起来那么困难)。

可以在 Defs 中了解%def的详细内容。

backtosectiontop

4<%namespace>

%namespace是Mako中相对Python 里import语句的等价物。

它允许访问其他模板文件的所有rendering函数和元数据,纯文本的python模块,以及局部定义的函数“包”。

<%namespacefile="functions.html"import="*"/>

%namespace编译后产生的对象是mako.runtime.Namespace的一个实例,这是在模块中被用来引用模板特定的信息(如当前的URI,继承结构以及其他一些东西)的一个中心结构,名称空间的详细描述在 Namespaces 中。

 

5<%inherit>

允许模板可以在继承链中安排其自身的位置。

这是其他很多模板语言都有的一个熟悉的概念。

<%inheritfile="base.html"/>

当使用%inherit标签时,首先,控制权被转交给继承树最顶层的父模板,由它来决定如何配合继承自它的子模板来处理其中的调用区域(callingareas)的内容。

Mako在这方面提供了很多灵活性,包括动态继承(dynamicinheritance),内容包装(contentwrapping),以及多态的方法调用(polymorphicmethodcalls).详见 Inheritance。

6<%call>

call标签用于调用<%defs%>标签,可传递额外的内嵌内容。

详细描述在 Callinga

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 成人教育 > 专升本

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1