本文发自 http://www.binss.me/blog/record-of-learning-tornado-3-template-extension/,转载请注明出处。

为了避免书写重复前端代码,提高前端代码的复用性,Tornado使用了模版拓展和模块两种机制来实现这个目的。

模版拓展

先写一个父模版base.html:

<html>
    <head>
        <title>mysite</title>
    </head>
    <body>
        <header>
            {% block header %}{% end %}
        </header>
        <content>
            {% block body %}{% end %}
        </content>
        <footer>
            {% block footer %}{% end %}
        </footer>
    </body>
</html>

子模版page_1.html可以通过拓展父模版实现其自身页面:

{% extends "base.html" %}

{% block header %}
    <h1>page_1</h1>
{% end %}

{% block body %}
    <p>Hello from the child template!</p>
{% end %}

{% block footer %}
    <p>page_1</p>
{% end %}

其做法是将父模版的所有内容复制进来,然后用 {% block 块名 %}{% end %} 包含的内容去替换父模版中相应的块。如果还有类似的页面page_2,那么只需按相同的块替换方法对base.html进行拓展即可。这种做法大大减少了前端重复代码量。

注意:一个语法错误或者没有闭合的 {% block %} 语句可以使得浏览器直接显示500: Internal Server Error。

模块

用于封装模板中包含的标记、样式以及行为,以便在同一模版或多个模版之间重复使用。

先定义html文件:modules/hello.html

<h1>Hello, {{ name }}</h1>

再定义控制器:

class HelloModule(tornado.web.UIModule):
    def render(self, name):
        return self.render_string('modules/hello.html', name=name)

还要在Application的settings字典中加 ui_modules={'Hello': HelloModule} 以声明模块。

定义了模块后,我们就可以在其他模版中引用它:如在index.html中加入:

{% for name in names %}
      {% module Hello(name) %}
{% end %}

index模版的控制器改为:

[python]

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('index.html',names=["dudu", "niang"])

访问后显示如下:

Hello, dudu
Hello, niang

这是因为在模版index.html中循环调用了两次Hello模块,根据传入的参数name生成了对应的句子并插入到模版中。这种做法亦减少了前端重复代码量,比起模版来,它更加灵活。

此外,Tornado还允许使用embedded_css和embedded_javascript方法嵌入其他的CSS和JavaScript来改变模块内容和样式。如:

class HelloModule(tornado.web.UIModule):
    def render(self, name):
        return self.render_string('modules/hello.html', name=name)

    def embedded_css(self):
        return ".name {background-color:#F5F5F5}"

    def embedded_javascript(self):
        return "document.write(\"hi!\")"

也可以通过以下函数直接嵌入文件:

def css_files(self):
    return "/static/css/name.css"

def javascript_files(self):
    return "/static/js/name.js"

还可以嵌入html代码:

def html_body(self):
    return "<div class="addition"><p>html_body()</p></div>"

总而言之,Tornado通过模版拓展和模块两种机制,减少了前端的重复代码,使代码更加整洁美观。如果你是学完Django再来学Tornado,那么你会对两者在模版方面高度的相似性而感到惊叹。