Tornado - 模板和数据库以及接口的调用顺序

接口调用顺序

方法

  • initialize():接受传递的参数
  • prepare()
    • 作用:预处理方法,在执行对应的请求方法之前调用
    • ⚠️注意:任何一种 HTTP 请求都会执行 prepare 方法
  • HTTP方法
    • get
    • post
    • head:类似 get 请求,只不过响应中没有具体的内容,用于获取报头
    • delete:请求服务器删除指定的资源
    • put:从客户端向服务器传送指定内容
    • patch:请求修改局部内容
    • options:返回 URL 支持的所有 HTTP 方法
  • set_default_headers()
  • write_error()
  • on_finish()
    • 作用:在请求处理结束后调用;在该方法中进行资源清理释放,或者是日志处理。
    • ⚠️注意:尽量不要在该方法中进行响应输出。

顺序

  • 在正常情况未抛出错误时
    1. set_default_headers
    2. initialize
    3. prepare
    4. HTTP方法
    5. on_finish
  • 在抛出错误时
    1. set_default_headers
    2. initialize
    3. prepare
    4. HTTP方法
    5. set_default_headers
    6. write_error
    7. on_finish

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class IndexHandler(RequestHandler):
def initialize(self):
print("initialize")

def prepare(self):
print("prepare")

def get(self, *args, **kwargs):
print("HTTP方法")
self.send_error(500)
self.write("sunck is a good man")

def set_default_headers(self):
print("set_default_headers")

def write_error(self, status_code, **kwargs):
print("write_error")
self.write("服务器内部错误……")

def on_finish(self):
print("on_finish")

模板

配置模板路径

1
2
3
settings = {
'template_path': os.path.join(BASE_DIRS, 'templates'),
}

渲染并返回给客户端

  • 使用 render() 方法

    1
    2
    3
    class HomeHandler(RequestHandler):
    def get(self, *args, **kwargs):
    self.render('home.html')

    index.py

  • templates -> home.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>主页</title>
    </head>
    <body>
    <h1>这里是home页面!</h1>
    </body>
    </html>

变量与表达式

  • 语法

    • {{ var }}
    • {{ expression }}
  • 示例

    1
    2
    3
    4
    class HomeHandler(RequestHandler):
    def get(self, *args, **kwargs):
    temp = 100
    self.render('home.html', num=temp)
    1
    2
    3
    4
    5
    6
    7
    8
    class HomeHandler(RequestHandler):
    def get(self, *args, **kwargs):
    num = 100
    per = {
    "name": "sunck",
    "age": 18
    }
    self.render('home.html', num=num, per=per)

    <h1>{{ per["name"] }}</h1>

    ⚠️注意:不能使用点语法

    1
    2
    3
    4
    5
    6
    7
    8
    class HomeHandler(RequestHandler):
    def get(self, *args, **kwargs):
    num = 100
    per = {
    "name": "sunck",
    "age": 18
    }
    self.render('home.html', num=num, **per)

    <h1>{{ age }}</h1>

流程控制

if

  • 格式

    1
    2
    3
    {% if 表达式 %}
    语句
    {% end %}
    1
    2
    3
    4
    5
    {% if 表达式 %}
    语句1
    {% else %}
    语句2
    {% end %}
    1
    2
    3
    4
    5
    6
    7
    8
    {% if 表达式1 %}
    语句1
    {% elif 表达式2 %}
    语句2
    ……
    {% elif 表达式n %}
    语句n
    {% end %}
  • 示例

    1
    2
    3
    {% if flag == 1 %}
    <h1>sunck is a good man</h1>
    {% end %}

for

  • 格式

    1
    2
    3
    {% for 变量 in 集合 %}
    语句
    {% end %}
  • 示例

    1
    2
    3
    4
    5
    <ul>
    {% for stu in stus %}
    <li>{{ stu["name"] }}</li>
    {% end %}
    </ul>

while

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class HomeHandler(RequestHandler):
def get(self, *args, **kwargs):
num = 100
per = {
"name": "sunck",
"age": 18
}
flag = 0
stus = [
{
"name": "hanmeimei",
"age": 20
},
{
"name": "lilei",
"age": 21
}
]
self.render('home.html', num=num, **per, flag=flag, stus=stus)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>主页</title>
</head>
<body>
<h1>这里是home页面</h1>
<h1>num: {{ num }}</h1>
<h1>num + 10: {{ num + 10 }}</h1>

<h1>{{ age }}</h1>

{% if flag == 1 %}
<h1>sunck is a good man</h1>
{% end %}

<ul>
{% for stu in stus %}
<li>{{ stu["name"] }}</li>
{% end %}
</ul>
</body>
</html>

函数

  • static_url()

    • 作用:获取配置的静态目录,并将参数拼接到静态目录后面并返回新的路径
    • 示例:<link rel="stylesheet" href="{{ static_url('css/home.css') }}">
    • 优点
      • 修改目录不需要修改 url
      • static_url 创建了一个基于文件内容的 hash 值,并将其添加到 URL 末尾 (当一个查询参数),这个 hash 值总能保证加载的都是最新的文件,而不是以前的缓存版本。不论是开发阶段还是上线阶段都是很有必要的。
  • 自定义函数

    1
    2
    3
    4
    5
    6
    class FuncHandler(RequestHandler):
    def get(self, *args, **kwargs):
    def mySum(n1, n2):
    return n1 + n2

    self.render('market.html', ms=mySum)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>闪送超市</title>
    </head>
    <body>
    <h1>{{ ms(100, 89) }}</h1>
    </body>
    </html>

转义

  • tornado 默认开启了自动转义功能,能防止网站受到恶意攻击

    1
    2
    3
    4
    class TransHandler(RequestHandler):
    def get(self, *args, **kwargs):
    str = "<h1>sunck is a good man</h1>"
    self.render('trans.html', str=str)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>转义</title>
    </head>
    <body>
    {{ str }}
    </body>
    </html>

    {{ str }}

  • 关闭自动转义(4 种方法)

    1. raw

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12

      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <title>转义</title>
      </head>
      <body>
      {% raw str %}
      {{ str }}
      </body>
      </html>

      ⚠️注意:只能关闭一行

    2. 在页面模板中修改:{% autoescape None %}

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <title>转义</title>
      </head>
      <body>
      {{ str }}
      {% autoescape None %}
      {{ str }}
      </body>
      </html>

      ⚠️注意:关闭当前文档的自动转义

    3. 在配置中修改:'autoescape': None

      1
      2
      3
      4
      5
      6
      settings = {
      'debug': False,
      'autoescape': None,
      'static_path': os.path.join(BASE_DIRS, 'static'),
      'template_path': os.path.join(BASE_DIRS, 'templates'),
      }

      ⚠️注意:关闭当前项目的自动转义

    4. escape() 函数

      • 作用:在关闭自动转义后,可以使用该方法对特定的变量进行转义
      • 示例
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        <!DOCTYPE html>
        <html lang="en">
        <head>
        <meta charset="UTF-8">
        <title>转义</title>
        </head>
        <body>
        {{ str }}
        {{ escape(str) }}
        {{ str }}
        </body>
        </html>

继承

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
{% block main %}

{% end %}
</body>
</html>

templates -> base.html

1
2
3
4
5
{% extends "base.html" %}

{% block main %}
<h1>这里是购物车页面</h1>
{% end %}

templates -> cart.html

1
2
3
class CartHandler(RequestHandler):
def get(self, *args, **kwargs):
self.render('cart.html', title="cart")

index.py
路由:(r'/gwc', index.CartHandler)

静态文件

  • static_path

    • 作用:告诉 tornado 从文件系统中的某一个特定的位置提供静态文件
    • 示例:'static_path': os.path.join(BASE_DIRS, 'static')
      1
      2
      3
      4
      5
      6
      settings = {
      'debug': False,
      'autoescape': None,
      'static_path': os.path.join(BASE_DIRS, 'static'),
      'template_path': os.path.join(BASE_DIRS, 'templates'),
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <title>主页</title>
      </head>
      <body>
      <h1>这是index页面!</h1>
      </body>
      </html>

      static -> html -> index.html

    • 请求方式:http://127.0.0.1:8000/static/html/index.html
    • 引入其他文件
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <title>主页</title>
      <!--<link rel="stylesheet" href="static/css/home.css">-->
      <link rel="stylesheet" href="{{static_url('css/home.css')}}">
      <script type="text/javascript" charset="utf-8" src="{{static_url('js/jquery.js')}}"></script>
      </head>
      <body>
      <h1>这是index页面!</h1>
      </body>
      </html>
  • StaticFileHandler

    • 使用原因:因为 http://127.0.0.1:8000/static/html/index.html 对于用户来说体验不佳
    • 本质:是 tornado 预制的用来提供静态资源文件的 handler
    • 作用:可以通过 tornado.web.StaticFileHandler 来映射静态文件
    • 示例
      1
      (r'/(.*)$', tornado.web.StaticFileHandler, {"path": os.path.join(config.BASE_DIRS, "static/html")})
      1
      2
      (r'/(.*)$', tornado.web.StaticFileHandler,
      {"path": os.path.join(config.BASE_DIRS, "static/html"), "default_filename": "index.html"})
    • 参数
      • path:用来指定提供静态文件的根路径
      • default_filename:用来指定访问路由中未指明文件名时,默认提供的静态文件
    • ⚠️注意 :最好在路由位置的最下面使用,否则其他的路由不能匹配

数据库

  • 概述

    • tornado 没有自带的 ORM,对于数据库需要自己去适配
    • 目前 Python3.6+Tornado 还没有比较完善的驱动
  • 连接

    • 在应用启动时创建一个数据库链接实例,供各个 RequestHandler 使用
    • RequestHandler 中通过 self.application 来获取其应用对象
  • Tornado 基础工程下载