tornado 学习笔记9 Tornado web 框架---模板(template)功能分析
2015-11-13 15:12
816 查看
Tornado模板系统是将模板编译成Python代码。
最基本的使用方式:
Loader这个类加载根目录的模板,然后缓存编译好的模板。
tornado模板系统不像其他模板系统,我们不会在表达式上设置任何限制。If和for语句块都会被精确地转成Python代码,所以你可以像下面一个使用复杂的表达式。
默认情况下,我们提供escape,url_escape,json_encode以及squeeze函数给所有的模板。
一般情况下,应用不会创建Template或者Loader实例,而是使用tornado.web.RquestHandler的render以及render_string方法,这两个方法根据Applicationsetting的template_path选项的值自动加载模板。
以_tt_开始的变量名称是被模板系统保留的,应用程序不能使用。
注释部分使用{#...#},从而注释部分会被忽略,而不会输出。
{%apply*function*%}….{%end%}
在apply和end之间对模板的所有输出应用函数。比如:
{%applylinkify%}{{name}}said:{{message}}{%end%}
{%block*name*%}...{%end%}表示一个命名的、可以被替换的块看,这个语法是针对模板继承的使用{%extends%}。在父模板中的块会被子模板同名的块中内容替换。比如:
{%comment...%}表示注释,是不会被输出的。注意这里没有{%end%}标签。
{%extends*filename*%}继承模板。
{%for*var*in*expr*%}...{%end%}跟Pythonfor循环语句相同。{%break%}和{%continue%}可以在循环内使用。
{%from*x*import*y*%} 跟Pythonimport语句一样
{%if*condition*%}...{%elif*condition*%}...{%else%}...{%end%}条件语句
{%import*module*%}跟Pythonimport语句一样
{%include*filename*%}引用其他模板文件。这个引用的文件可以看到所有的本地变量,因为他们都被直接复制。相反地,{%moduleTemplate(filename,**kwargs)%}被用来包含其他在隔离命名空间的模板。
{%set*x*=*y*%}设置值
{%try%}...{%except%}...{%else%}...{%finally%}...{%end%}跟Python的异常处理一样。
{%while*condition*%}...{%end%}跟Python的while语句一样。
构造函数:
(1)
(2)对autoescape的设置。autoescape是一个函数,默认为“xhtml_escape”函数
(3)对namespace命名空间的设置。如果设置了loader,则为loader的namespace.
作用:根据给定的参数,生成模板,最后是生成模板的结果,是一个字符串。
参数:
kwargs:是一个namespace的字典,都是一个方法的映射。
当你使用像“{%extends%}”、{%include%}这些模板语法时,你必须使用模板加载器。当模板第一次加载完毕后,加载器会缓存这些模板。
构造函数:
参数:
autoescape:是否自动转义。要么是None值,要么是在模板namespace中的函数名,比如是”xhtml_escape”
namespace:模板中使用的方法的映射字典。
处理过程:
主要是对相关属性的初始化。注意,最后一句self.lock=threading.RLock()是为了考虑多线程并发的存在,加上线程锁。
reset方法
重设加载器的模板,清除缓存
resolve_path方法
将模板的相对路径转换成绝对路径,由子类继承
load方法
加载模板。调用了resolve_path以及_create_template方法,这两个方法都有子类实现。
构造函数:
参数:
root_directory:根路径
kwargs:参数字典
处理过程:
调用父类初始化过程,同时设置root属性,为绝对路径
resolve_path方法
实现BaseLoader父类中的方法。
就是讲各种路径合并,然后得到模板的绝对路径,最后去除根路径,返回剩余的路径。
_create_template方法
根据模板的绝对路径,打开模板文件,然后实例化Template对象并返回。实例化的Template对象会缓存在加载器中。
最基本的使用方式:
t=template.Template("<html>{{myvalue}}</html>") printt.generate(myvalue="XXX")
Loader这个类加载根目录的模板,然后缓存编译好的模板。
tornado模板系统不像其他模板系统,我们不会在表达式上设置任何限制。If和for语句块都会被精确地转成Python代码,所以你可以像下面一个使用复杂的表达式。
{%forstudentin[pforpinpeopleifp.studentandp.age>23]%} <li>{{escape(student.name)}}</li> {%end%}
###Pythoncode defadd(x,y): returnx+y template.execute(add=add) ###Thetemplate {{add(1,2)}}
默认情况下,我们提供escape,url_escape,json_encode以及squeeze函数给所有的模板。
一般情况下,应用不会创建Template或者Loader实例,而是使用tornado.web.RquestHandler的render以及render_string方法,这两个方法根据Applicationsetting的template_path选项的值自动加载模板。
以_tt_开始的变量名称是被模板系统保留的,应用程序不能使用。
9.1语法
模板表达式使用双方括号{{…}}包围。里面内容可以是任何python的表达式,里面的内容根据当前的autoescape设置而决定是否进行转义。其他模板指令使用{%...%}.如果你需要将{{或者{%原样输出,你可以使用{{!和{%!进行转义。注释部分使用{#...#},从而注释部分会被忽略,而不会输出。
{%apply*function*%}….{%end%}
在apply和end之间对模板的所有输出应用函数。比如:
{%applylinkify%}{{name}}said:{{message}}{%end%}
{%block*name*%}...{%end%}表示一个命名的、可以被替换的块看,这个语法是针对模板继承的使用{%extends%}。在父模板中的块会被子模板同名的块中内容替换。比如:
<!--base.html-->
<title>{%blocktitle%}Defaulttitle{%end%}</title>
<!--mypage.html-->
{%extends"base.html"%}
{%blocktitle%}Mypagetitle{%end%}
{%comment...%}表示注释,是不会被输出的。注意这里没有{%end%}标签。
{%extends*filename*%}继承模板。
{%for*var*in*expr*%}...{%end%}跟Pythonfor循环语句相同。{%break%}和{%continue%}可以在循环内使用。
{%from*x*import*y*%} 跟Pythonimport语句一样
{%if*condition*%}...{%elif*condition*%}...{%else%}...{%end%}条件语句
{%import*module*%}跟Pythonimport语句一样
{%include*filename*%}引用其他模板文件。这个引用的文件可以看到所有的本地变量,因为他们都被直接复制。相反地,{%moduleTemplate(filename,**kwargs)%}被用来包含其他在隔离命名空间的模板。
{%set*x*=*y*%}设置值
{%try%}...{%except%}...{%else%}...{%finally%}...{%end%}跟Python的异常处理一样。
{%while*condition*%}...{%end%}跟Python的while语句一样。
9.2关联的类
tornado.template.Template
源代码位于site-packages>tornado>template.py,这个类表示已编译好的模板。
构造函数:
def__init__(self,template_string,name="<string>",loader=None,
compress_whitespace=None,autoescape=_UNSET):
参数:
template_string:模板字符串
name:模板名称
loader:模板加载器
compress_whitespace:是否压缩空白字符
autoescape:是否自动转义
实现代码:
self.name=name
ifcompress_whitespaceisNone:
compress_whitespace=name.endswith(".html")or\
name.endswith(".js")
ifautoescapeisnot_UNSET:
self.autoescape=autoescape
elifloader:
self.autoescape=loader.autoescape
else:
self.autoescape=_DEFAULT_AUTOESCAPE
self.namespace=loader.namespaceifloaderelse{}
reader=_TemplateReader(name,escape.native_str(template_string))
self.file=_File(self,_parse(reader,self))
self.code=self._generate_python(loader,compress_whitespace)
self.loader=loader
try:
#Underpython2.5,thefakefilenameusedheremustmatch
#themodulenameusedin__name__below.
#Thedont_inheritflagpreventstemplate.py'sfutureimports
#frombeingappliedtothegeneratedcode.
self.compiled=compile(
escape.to_unicode(self.code),
"%s.generated.py"%self.name.replace('.','_'),
"exec",dont_inherit=True)
exceptException:
formatted_code=_format_code(self.code).rstrip()
app_log.error("%scode:\n%s",self.name,formatted_code)
raise
处理过程:
(1)
对compress_whitespace的值进行设置。如果是None,如果模板是html或者js文件,则compress_whitespace为True.
(2)对autoescape的设置。autoescape是一个函数,默认为“xhtml_escape”函数
(3)对namespace命名空间的设置。如果设置了loader,则为loader的namespace.
(4)
设置内部类_TemplateReader类型的reader.
(5)
设置file、code属性。
(6)
最后调用compile方法,进行模板编译。
generate方法
defgenerate(self,**kwargs):
"""Generatethistemplatewiththegivenarguments."""
namespace={
"escape":escape.xhtml_escape,
"xhtml_escape":escape.xhtml_escape,
"url_escape":escape.url_escape,
"json_encode":escape.json_encode,
"squeeze":escape.squeeze,
"linkify":escape.linkify,
"datetime":datetime,
"_tt_utf8":escape.utf8,#forinternaluse
"_tt_string_types":(unicode_type,bytes),
#__name__and__loader__allowthetracebackmechanismtofind
#thegeneratedsourcecode.
"__name__":self.name.replace('.','_'),
"__loader__":ObjectDict(get_source=lambdaname:self.code),
}
namespace.update(self.namespace)
namespace.update(kwargs)
exec_in(self.compiled,namespace)
execute=namespace["_tt_execute"]
#Clearthetracebackmodule'scacheofsourcedatanowthat
#we'vegeneratedanewtemplate(mainlyforthismodule's
#unittests,wheredifferenttestsreusethesamename).
linecache.clearcache()
returnexecute()
作用:根据给定的参数,生成模板,最后是生成模板的结果,是一个字符串。
参数:
kwargs:是一个namespace的字典,都是一个方法的映射。
tornado.template.BaseLoader
模板加载器的基类。当你使用像“{%extends%}”、{%include%}这些模板语法时,你必须使用模板加载器。当模板第一次加载完毕后,加载器会缓存这些模板。
构造函数:
def__init__(self,autoescape=_DEFAULT_AUTOESCAPE,namespace=None):
"""``autoescape``mustbeeitherNoneorastringnamingafunction
inthetemplatenamespace,suchas"xhtml_escape".
"""
self.autoescape=autoescape
self.namespace=namespaceor{}
self.templates={}
#self.lockprotectsself.templates.It'sareentrantlock
#becausetemplatesmayloadothertemplatesvia`include`or
#`extends`.NotethatthankstotheGILthiscodewouldbesafe
#evenwithoutthelock,butcouldleadtowastedworkasmultiple
#threadstriedtocompilethesametemplatesimultaneously.
self.lock=threading.RLock()
参数:
autoescape:是否自动转义。要么是None值,要么是在模板namespace中的函数名,比如是”xhtml_escape”
namespace:模板中使用的方法的映射字典。
处理过程:
主要是对相关属性的初始化。注意,最后一句self.lock=threading.RLock()是为了考虑多线程并发的存在,加上线程锁。
reset方法
重设加载器的模板,清除缓存
resolve_path方法
将模板的相对路径转换成绝对路径,由子类继承
load方法
加载模板。调用了resolve_path以及_create_template方法,这两个方法都有子类实现。
defload(self,name,parent_path=None):
"""Loadsatemplate."""
name=self.resolve_path(name,parent_path=parent_path)
withself.lock:
ifnamenotinself.templates:
self.templates[name]=self._create_template(name)
returnself.templates[name]
tornado.template.Loader
模板加载器,继承BaseLoader,从单一根路径加载。构造函数:
def__init__(self,root_directory,**kwargs):
super(Loader,self).__init__(**kwargs)
self.root=os.path.abspath(root_directory)
参数:
root_directory:根路径
kwargs:参数字典
处理过程:
调用父类初始化过程,同时设置root属性,为绝对路径
resolve_path方法
实现BaseLoader父类中的方法。
defresolve_path(self,name,parent_path=None):
ifparent_pathandnotparent_path.startswith("<")and\
notparent_path.startswith("/")and\
notname.startswith("/"):
current_path=os.path.join(self.root,parent_path)
file_dir=os.path.dirname(os.path.abspath(current_path))
relative_path=os.path.abspath(os.path.join(file_dir,name))
ifrelative_path.startswith(self.root):
name=relative_path[len(self.root)+1:]
returnname
就是讲各种路径合并,然后得到模板的绝对路径,最后去除根路径,返回剩余的路径。
_create_template方法
def_create_template(self,name):
path=os.path.join(self.root,name)
withopen(path,"rb")asf:
template=Template(f.read(),name=name,loader=self)
returntemplate
根据模板的绝对路径,打开模板文件,然后实例化Template对象并返回。实例化的Template对象会缓存在加载器中。
相关文章推荐
- Storm系列(二十)分区事务PartitionTransaction及示例
- 二叉树遍历的前驱和后继
- struct2源码解读(8)之container原理
- 年华依在,阳光正好
- strcpy_s 与 strcpy 的用法
- 解决 anyconnect was net able to establish a connection to the specified secure gateway
- show_rle_picture
- 被误解的MVC和被神化的MVVM
- linux 内核常用知识笔记
- 如何制作宽屏页面之html简单方法
- java多线程通信方法
- WinPcap笔记(2):获取设备列表
- mysql 中某一列字符串中特定字符以后的内容
- tomcat下solr初使用-windows
- laravel安装
- 3.系统简单优化/二进制辨析-讲义大纲
- C语言中static的作用及C语言中使用静态函数有何好处
- ViewPager引用错误的资源地址的图片导致的OOM问题
- Unity中资源动态加载的几种方式比较
- OpenGL ES 2.0总结(2)-纹理