Tornado学习笔记第三篇-tornado的web基础下篇

RequestHandler的两个子类StaticFileHandler,RedirectHandler

这个小节我们学习下RequestHandler的两个子类。

首先学习下RedirectHandler

进行重定向

一般是在实例化app的时候将一个不再使用的路由永久重定向到另一个路由。

1
2
3
4
app = web.Application([
("/", MainHandler),
("/2/", RedirectHandler, {"url":"/"}),
], debug=True)

这里我们将/2/的路由永久重定向到/路由下。

看下RedirectHandler的源码:

1
2
3
4
5
6
7
8
9
10
11
12
class RedirectHandler(RequestHandler):
"""Redirects the client to the given URL for all GET requests.

You should provide the keyword argument ``url`` to the handler, e.g.::

application = web.Application([
(r"/oldpath", web.RedirectHandler, {"url": "/newpath"}),
])
"""
def initialize(self, url, permanent=True):
self._url = url
self._permanent = permanent

我们看到默认情况下的permanent设置为True

我们知道在RequestHandler中也有一个重定向方法redirect

我们看下redirect的源码:

1
2
3
4
5
6
7
8

def redirect(self, url, permanent=False, status=None):
"""Sends a redirect to the given (optionally relative) URL.
If the ``status`` argument is specified, that value is used as the
HTTP status code; otherwise either 301 (permanent) or 302
(temporary) is chosen based on the ``permanent`` argument.
The default is 302 (temporary).
"""

redirect主要是代码内部做临时重定向,如访问未登录的接口重定向到登录接口。

两者的区别:

一般RedirectHandler的用在url配置的时候做永久重定向。

redirect一般写在业务逻辑中,根据业务逻辑决定是否需要重定向。

再看下StaticFileHandler

这个主要代理静态文件:html,css,js,图片等。

我们可以使用初始化app的时候修改配置来指定静态文件的访问格式。

1
2
3
4
5
6
7
8
settings = {
"static_path": "tornado_overview/chapter02/static",
"static_url_prefix": "/static/"
}

app = web.Application([
("/", MainHandler),
], debug=True, **settings)

或者直接使用StaticFileHandler:

1
2
3
application = web.Application([
(r"/static/(.*)", web.StaticFileHandler, {"path": "/var/www"}),
])
tornado的template

tornado 的模板渲染我们可以类比其他框架的,例如Flask

我们是可以直接返回一段html文本

1
self.finish("<h1>tornado</h1>")

文本中可以传入变量

1
2
word = "tornado"
self.finish(f"<h1>{word}</h1>")

Web 框架都有模板功能

我们看下tornado中的模板功能

1
2
3
4
5
6
7
8
9
from tornado.web import template


word = "tornado"
# 这里和 jinja2 的类似
t = template.Template("<h1>{{ word }}</h1>")

# 将上面设置的变量 word 放到模板中
self.finish(t.generate(word=word))

如果想渲染整个html文件,需要使用render函数、

1
self.render("index.html", orders=orders)

我们调用完render就不要再调用writer了,因为该函数最后调用了finish

上面的功能可以类比Flask的模板渲染

1
2
3
from flask import render_template

return render_template("index.html", orders=orders)

Flask一样我们需要指定模板文件夹所在位置

1
2
3
settings = {
"template_path": "templates" # 相对于配置文件所在的相对位置
}
由购物车列表页学习 template常用功能
  1. 首先看下模板中的静态文件的引用

    我们通过配置static_path指定了静态文件的位置,static_url_prefix指定静态文件的前缀。在模板文件中,我们可以方便的引用静态文件。

    1
    <link rel="stylesheet" type="text/css" href="{{ static_url('css/base.css') }}">

    使用static_url函数将相对于我们指定的static_path文件位置作为参数。

    这个类似比下Flask中的url_for

    1
    <script src="{{ url_for('static', filename='js/jquery.min.js') }}"></script>
  2. 在模板中使用后台传过来的数据,这个和jinja2基本一致

    我们实现这样一个页面渲染

    image-20181105164830823

    渲染循环

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    {% for order in orders %}
    <dd class="item clearfix">
    <div class="item-row">
    <div class="col col-1">
    <div class="g-pic">
    <img src="{{ order['image'] }}" srcset="{{ order['image'] }} 2x" width="40" height="40">
    </div>
    <div class="g-info">{{ order['name'] }}</div>
    </div>
    <div class="col col-2">{{ order['price'] }}元</div>
    <div class="col col-2">{{ order['nums'] }}</div>
    <div class="col col-2">{{ order['price']*order['nums'] }}元</div>
    <div class="col col-2">{% raw order['detail'] %} </div>#}
    </div>
    </dd>
    {% end %}

    这个和jinja2类似,直接计算两个变量乘法

    1
    2
    3
    {{ order['price']*order['nums'] }}

    引用原生的`html`元素`{% raw order['detail'] %}`(其中`detail`为:`"detail": "<a href='http://www.baidu.com'>查看详情</a>"`)进行字符转义。
上面的乘法可以由后台传入一个计算方法。

1
2
def cal_total(price, nums):
return price*nums

将方法的引用传入到模板中可以直接使用方法。

1
2
{% from chapter02.utils import cal_total %}
<div class="col col-2">{{ cal_total(order['price'],order['nums']) }}元</div>

设置变量

1
{% set total = 0 %}
template的页面继承和重载

tornado的模板继承和重载机制和jinja2基本一致,暂时不详细记录笔记。

1
{% extends 'base.html' %}
tornado模板中UIModule

tornado的模板文件可以像vue等前端框架一样进行组件化开发。

首先我们创建一个Module复用类:

1
2
3
4
5
6
class OrderModule(tornado.web.UIModule):
def cal_total(self, price, nums):
return price * nums

def render(self, order, *args, **kwargs):
self.render_string("ui_modules/order-list.html")

其中order-list.html为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dd class="item clearfix">
<div class="item-row">
<div class="col col-1">
<div class="g-pic">
<img src="{{ order['image'] }}" srcset="{{ order['image'] }} 2x" width="40" height="40">
</div>
<div class="g-info">{{ order['name'] }}></div>

<div class="col col-2">{{ order['price'] }}元</div>
<div class="col col-2">{{ order['nums'] }}</div>
<div class="col col-2">{{ order['price']*order['nums'] }}元</div>
<div class="col col-2">{% raw order['detail'] %} </div>
</div>
</div>
</dd>

settings中设置ui_modules,值为键值对。

1
2
3
4
5
6
7
8
settings = {
"static_path":"static",
"static_url_prefix":"/static/",
"template_path": "templates",
"ui_modules": {
"OrderModule":OrderModule
}
}

在模板中引用我们抒写的模块

1
{% module OrderModule(order) %}

除了可以复用html外还可以复用css,js文件。

tornado的settings

这个小节我们看下settings有哪些值是可以配置的。

我们看下官方文档:tornado的settings有哪些

知识就是财富
如果您觉得文章对您有帮助, 欢迎请我喝杯水!