据limodou的文档介绍,uliweb的模板是基于webpy框架的模板,是一种非常简洁的模板表示方式,语法很简单,除了标准的html语言外,还可以包含下面介绍的语法代码,需要注意的是,这些语法代码中的名称都是由view函数通过字典返回的key值来表示的。
所有与Python相关的模板代码均需要放置在{{}}之中!
{{ = result }} 用来输出标记,result可以为一个变量或者一个函数调用,系统会自动对输出的内容进行转义处理,需要注意的是 = 与reuslt之间有一个空格,或者=左右均无空格,这原本是一个bug,在发了一份邮件给limodou后,马上就修正了。
如果result是一个函数func,{{ = func }} 将得到func的repr显示,如果需要调用函数,则需要将代码编写成 {{ = func() }},这是一个非常有用的方法,可以在html中调用各类合适的方面的内部函数,其实这是一个任何一个合法的Python语句都可以的函数,如果我们故意将这个函数写错,在http://localhost:8000/主页面上将显示出错误消息,在最后一行,可以看到是采用out.write(func())方式写出html代码的,因此只要是合法的代码(能够返回一个string对象)的值,都可以作为out.write()的参数,既然我们知道了{{=}}中的内容是作为out.write参数,而且为string对象,那么我们也可以直接使用{{="your"}}来输出一个字符串,尽管"your"并不是我们从view中获取得到的一个变量,但是它确实可以使用!!
从上面的分析我们也可以知道,模板的代码最终都将会转换成python中的代码,那么任何内嵌的函数都是可以使用的,由此我们可以构建一个复杂的函数来输出我们当前文件的内容
{{ }} 语句块中包含的是Python的代码语句,此Python语句需要pass语句块来进行结束。如果在模板中编写如下代码:
{{ for local in dic: }}
{{=local }}
{{ pass}}
在uliweb后台,将执行下面的代码:
out.write('\n\n', escape=False)
for local in dic:
out.write('\n', escape=False)
out.write(local)
out.write('\n', escape=False)
pass
out.write('\n\n', escape=False)
因此我们很容易在{{}中编写Python语句,在{{=}}中使用Python的变量,或者函数等内容!
{{ extend template }} 将扩展有template指定的模板,template可以为字符串,表示从父模板中继承,在最新的版本中,在原先的教程中,说是需要在父模板中定义一个{{include }},这样在{{extend}}之后的所有内容都将插入到这个位置,但是如果在{{extend}}之前还有内容将插入到父模板的最前面去。通过这种方式就可以在子模板中定义变量,但是在父模板中使用。就是将变量的定义放在{{extend}}之前就行了!
也可以通过include方式载入模板,常用的一个模板是menu,一般在extend模板之后include的。
menu模板的定义如下:
{{
menus = [
('settings', 'Settings', '/admin'),
('appsinfo', 'Apps Info', '/admin/appsinfo'),
('urls', 'Urls', '/admin/urls'),
#('application',"Application", '/admin/app'),
#("variable","Variable","/admin/var"),
('request', "Request", "/admin/request"),
]
def menu(current='settings'):
for id, caption, link in menus:
if id == current:
out.write('<li id="current"><strong>%s</strong></li>' % caption, escape=False)
else:
out.write('<li><a href="%s">%s</a></li>' % (link, caption), escape=False)
pass
pass
pass
}}
通过include menu模板之后,之后就可以调用menu函数进行输出处理。
不建议那么使用,而且在最新的版本中,include template方法有些无奈![ubunoon] 可以在父template中定义某个块 {{ block main }} 方式,然后在子模板用 {{ block mian }} {{end}} 语句块来取代父模板中的内容。这个与django的模板方式有些类似!
我们已经分析得知,模板是运行在Python环境下,那么template中实际具有那些特殊的环境呢?
Uliweb首先为我们内置了一些常用函数(方法):
xml(text) 用来输出不转移的字符,可以用来输出HTML代码,如果有一段文本,里面包含了<>等具有特殊意义的HTML字符,可以通过xml来实现正确输出。
out对象,用来输出信息,从上面分析我们已经看到,所有的{{=}}都是通过out对象的write方法来进行输出,该方法也可以直接作为python语句在模板中进行应用。{{= result}}与{{ out.write(result) }} 是等同的。
out对象一般不需要直接在模板中使用,具有两个特殊的方法:
write(text, escape = True) 输出文本,escape表示是否要进行转义
noescape(text) 输出不需要进行转义的文本
由此我们可以得到,xml(text)其实就是使用write(text,False)方式进行处理,只是使用xml方便一些。我们可以在模板中通过调用{{=xml}}与{{=out.write}}来查看输出的是否为同一个对象的同一个地址,我的测试结果如下:
<bound method Out.noescape of <uliweb.core.template.Out object at 0x02EAB490>>
<bound method Out.write of <uliweb.core.template.Out object at 0x02EAB490>>
很明显,xml与out.write使用同一个方法,只是xml调用的Out.noescape方法。
在最新的版本中,增加了一个{{ << }} 功能,和{{xml()}}具有相同的功能,也就是{{ <<val }} 与 {{ xml(var) }}具有相同的功能,由于<<只是一个符号,因此无法通过测试其调用地址!!查看源代码就可以知道,{{<<}}与{{xm()}}只是在解析时不同,最后仍是通过Out.write对象来调用的。
同时,模板还支持一个url_for的反转方法,url_for方法可以将调用获取的url地址进行反转获取。
如果要给自己的增加自己定义的函数,则需要在app目录下面修改__init__.py文件,在里面添加代码:
from uliweb.core.plugin import plugin
##################################################
# insert rst2html function to template environment
##################################################
@plugin('prepare_template_env')
def prepare_template_env(sender, env):
from uliweb.utils.rst import to_html
from uliweb.core.SimpleFrame import errorpage
def rst2html(filename):
f = env.get_file(filename)
if f:
return to_html(file(f).read())
else:
errorpage("Can't find the file %s" % filename)
env['rst2html'] = rst2html
系统会自动调用prepare_template_env函数,从而将模板功能rst2html添加到环境中去。在prepare_template_env函数下面定义内嵌函数,所有相关的内嵌函数通过env[]字典方式,都可以添加到模板方法中去。
模板采用utf-8进行编码,因此最好将所有的字符均用utf-8进行处理,所有的文档也保存为utf-8格式。在父模板中设置的charset=gb2312并不会起作用!
Uliweb的模板技术是在不断的更新与变化之中的,因此需要不断关注uliweb,了解其技术发展。
这个分析的uliweb模板,也不是最新版本的。