tornado 学习笔记8 模板以及UI
Tornado 包含一个简单、快速而且灵活的模板语言。
Tornado同样可以使用任何其他的python模板语言,虽然没有集成这些模板语言进RequestHandler.render方法中。将模板渲染成字符串,然后传递给RequestHandler.write方法。
8.1 配置模板
默认的,tornado在跟引用模板文件的py文件同一个文件目录中去查找模板文件。在不同的目录下放置模板文件,在Application setting中设置template_path选项(或者如果你想为不同的hanlder使用不同的模板路径,你可以重写RequestHandler.get_template_path方法)。
从non_filesystem位置加载模板,继承tornado.template.BaseLoader,编写其子类,然后给application setting中的template_loader选项设值。
默认情况下,编译后的模板会被缓存。关闭这个缓存然后重新加载,这样在模板文件的更新总是可见的,实现这个功能,将applcation中compliled_template_cache设值成False或者debug设置成True.
8.2 模板语法
Tornado模板仅仅是HTML(或者其他文件格式的文件),使用了Python控制序列以及在标记中嵌入表达式。例如:
<html> <head> <title>{{ title }}</title> </head> <body> <ul> {% for item in items %} <li>{{ escape(item) }}</li> {% end %} </ul> </body> </html>
如果你这个模板保存为“template.html”,然后将其与你的Python文件放置在同一个目录中,你可以使用以下方式渲染你的模板。
class MainHandler(tornado.web.RequestHandler): def get(self): items = ["Item 1", "Item 2", "Item 3"] self.render("template.html", title="My title", items=items)
tornado模板支持控制语句和表达式。控制语句用{% %}包裹,比如{% if len(items) > 2 %}.表达式用{{ }}包裹,比如{{ items[0] }}。
控制语句或多或少与Python语句精确映射。支持if、for 、while 以及try语句,所有的语句都以 {% end %}结束。使用extends 和block语句,同样支持模板的继承。
表达式可以是任何Python表达式,甚至包括方法的调用。模板代码在包含以下对象和方法的名称空间中执行。
- l escape :tornado.escape.xhtml_escape 的别名
- l xhtml_escape : tornado.escape.xhtml_escape 的别名
- l url_escape : tornado.escape.url_escape 的别名
- l json_encode : tornado.escape.json_encode 的别名
- l squeeze: tornado.escape.squeeze的别名
- l linkify:tornado.escape.linkify的别名
- l datetime : Python 的datetime模块
- l handler:当前RequestHandler对象
- l request : handler.request属性
- l current_user : handerl.current_user属性
- l locale :hanlder.locale属性
- l _: hanlder.locale.translate 的别名
- l static_url :handler.static_url的别名
- l xsrf_form_html :hanlder. xsrf_form_html的别名
- l reverse_url :Application. reverse_url的别名
- l 来自Application Settings中的ui_methods以及ui_modules的入口
- l 所有传递给render 或者render_string函数的关键字参数
默认情况下,所有的模板输出都是编码转义的,使用tornado.escape.xhtml_escape函数。通过传递autoescape=None的参数给Application或者tornado.template.Loader构造函数,可以全局改变这种行为。而对于一个模板文件,可以使用{% autoescape None %}指令,或者对于单一表达式,使用{% raw %}替代{{ }}.
注意,尽管在避免XSS缺陷方面,自动的转义是非常有用的,但是并不是在所有的情况都是有效的。在某种情况下出现的表达式,比如在Javascript或者CSS中,可能需要额外的转义。具体查看http://wonko.com/post/html-escaping
8.3 UI modules
Tornado支持UI modules,这样使得支持标准、可复用的UI widgets更加容易。UI modules向特别的函数调用,用来渲染页面的组件,而且他们可以用他们自身的CSS 和Javascript 打包在一起。
举个例子,如果你正在实现一个博客网站,你可能想使得博客入口同时出现在博客的网站的首页以及每一个博客页面,你可以使用Entry 模块去渲染他们。首先,为你的UI modules创建一个Python模块,比如uimodules.py.代码如下:
class Entry(tornado.web.UIModule): def render(self, entry, show_comments=False): return self.render_string( "module-entry.html", entry=entry, show_comments=show_comments)
然后在application的设置中使用ui_modules选项告诉tonado使用uimodules.py。代码如下:
from . import uimodules class HomeHandler(tornado.web.RequestHandler): def get(self): entries = self.db.query("SELECT * FROM entries ORDER BY date DESC") self.render("home.html", entries=entries) class EntryHandler(tornado.web.RequestHandler): def get(self, entry_id): entry = self.db.get("SELECT * FROM entries WHERE id = %s", entry_id) if not entry: raise tornado.web.HTTPError(404) self.render("entry.html", entry=entry) settings = { "ui_modules": uimodules, } application = tornado.web.Application([ (r"/", HomeHandler), (r"/entry/([0-9]+)", EntryHandler), ], **settings)
在模板中,就可以通过{% module % }语句调用module.这样你可以在home.html以及entry.html中调用Entry模块。
home.html 代码如下:
{% for entry in entries %}
{% module Entry(entry) %}
{% end %}
而,entry.html代码如下:
{% module Entry(entry, show_comments=True) %}
Modules通过重写embedded_css,embedded_javascript,javascript_files或者css_files方法可以包括自定义的CSS和JavaScipt函数,代码如下:
lass Entry(tornado.web.UIModule): def embedded_css(self): return ".entry { margin-bottom: 1em; }" def render(self, entry, show_comments=False): return self.render_string( "module-entry.html", show_comments=show_comments)
Module的css和Javascript只会加载一次,而不管这个模块在页面使用很多次。CSS总是被包括在<head>头部,而javascript总是被包含在</body>标签之前。