Tornado框架03-路由系統

貓xian森發表於2017-03-16

Tornado中支援兩種路由系統, 正則路由系統以及二級域名路由系統.

# 預設路由系統, 根據url的不容呼叫不同的類
application = tornado.web.Application([
    (r"/index/(?P<page>\d*)", home.IndexHandle),
], **settings)

#二級路由匹配
application.add_handlers("test.ming.com",[
    (r"/index/(?P<page>\d*)", home.IndexHandle)
])複製程式碼
  • (r"/index/(?P<page>\d*)", home.IndexHandle) 這裡我們訪問時候需要以類似http://127.0.0.1/index/2的方式訪問, 在get或者post接受處理請求的函式應有page引數來接受訪問地址最後的整數(我們稍後將根據這個做一個分頁的demo)
  • 當我們加入二級域名時候, 預設訪問網站執行第一個預設路由系統, 僅當我們訪問設定的二級域名才會呼叫對應的處理器(當前程式碼指的是test.ming.com的域名)

接下來我們使用基於正則的路由系統來實現網頁分頁功能.

Tornado框架03-路由系統
專案目錄

all.py檔案如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

#利用全域性變數模擬資料庫所有內容
USER_LIST= [
    {'username': 'test', 'email': 'test@163.com'}
]

#利用迴圈生成多條資料來模擬大量資料依次便於實現分頁效果
for i in range(300):
    tmp = {'username': "test - " + str(i), 'email': str(i) + "@vip.com"}
    USER_LIST.append(tmp)複製程式碼

pager.py檔案如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

# 單獨用於實現分頁功能的類
class Page:
    # current_page表示當前頁數, all_item表示總的資料條目
    # 初始化時候將當前頁數current_page與總頁數all_page加入到物件中
    def __init__(self, current_page, all_item):
        # all_page表示總頁數, 每頁顯示5條資料, more表示餘數, 如果大於0則表示應多加一頁才能顯示完所有的資料
        all_page, more = divmod(all_item, 5)
        if more > 0:
            all_page += 1
        self.all_page = all_page

        # 捕捉異常, 防止傳入非法字元冒充頁數, 一旦發生異常則直接將當前頁current_page設定為1, 表示預設顯示第一頁
        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        # 如果前傳入的頁數小於1, 則直接預設為第一頁
        if current_page < 1:
            current_page = 1
        self.current_page = current_page

    # 根據當前頁在每個頁面顯示11個頁碼, 此處是開始頁碼
    @property
    def start_page(self):
        return (self.current_page - 1) * 5

    # 結束頁碼
    @property
    def end_page(self):
        return self.current_page * 5

    # 顯示的頁碼對應的html字串, base_url表示可定製的url跳轉路徑
    def page_str(self, base_url):
        # 定義list_page列表用來暫時儲存所有的頁碼字串
        list_page = []

        # 如果總頁數小於11頁, 則直接顯示所有頁數
        if self.all_page < 11:
            s = 0
            e = self.all_page

        # 總頁數大於11頁時候
        else:
            # 當前頁數小於6則直接顯示1到11頁
            if self.current_page <= 6:
                s = 1
                e = 11

            # 當前頁數大於6頁時候
            else:
                # 當前頁加上5也之後就大於總頁數則直接顯示倒數11頁
                if self.current_page + 5 > self.all_page:
                    s = self.all_page - 10
                    e = self.all_page

                # 當前頁數大於6頁並且加上5頁並不超過總頁數時候, 顯示當前頁前後5頁以及當前頁
                else:
                    s = self.current_page - 5
                    e = self.current_page + 5

        # 首頁設定
        first_page = '<a href="/%s/1">首頁</a>' % (base_url)
        list_page.append(first_page)

        # 上一頁設定
        # 當前頁小於等於第一頁時候, 點選上一頁不做任何操作(這裡理論上是不會有小於的情況)
        if self.current_page <= 1:
            pre_page = '<a href="javascript:void(0);">上一頁</a>'

        # 當前頁大於第一頁, 點選上一頁則直接跳轉到上一頁
        else:
            pre_page = '<a href="/%s/%s">上一頁</a>' % (base_url, self.current_page - 1)
        list_page.append(pre_page)

        # 根據上邊條件過濾後的頁碼起始位置s以及頁碼終止位置e來生成對應的11條頁碼對應的html字串
        for p in range(s, e + 1):
            if p == self.current_page:
                tmp = '<a class="active" href="/index/%s">%s</a>' % (p, p)
            else:
                tmp = '<a href="/%s/%s">%s</a>' % (base_url, p, p)
            list_page.append(tmp)

        # 下一頁設定
        # 下一頁要大於或者等於最大頁數時候, 不做任何操作
        if self.current_page >= self.all_page:
            next_page = '<a href="javascript:void(0);">下一頁</a>'
        else:
            next_page = '<a href="/%s/%s">下一頁</a>' % (base_url, self.current_page + 1)
        list_page.append(next_page)

        # 尾頁設定
        last_page = '<a href="/%s/%s">尾頁</a>' % (base_url, self.all_page)
        list_page.append(last_page)

        # 頁面跳轉
        jump_page = """<input type="text" /><a onclick='JumpTo("%s",this)'>GO</a>""" % base_url
        # 頁面跳轉的js程式碼, 本質就是location.href的使用
        jspt = """<script>
            function JumpTo(base_url,th){
                var val=th.previousElementSibling.value;
                if(val.trim().length>0){
                    location.href="/"+base_url+"/"+val
                }
            }
        </script>"""
        list_page.append(jump_page)
        list_page.append(jspt)
        return "".join(list_page)複製程式碼

home.py檔案如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.web
from commons.all import USER_LIST
from commons.pager import Page

class IndexHandle(tornado.web.RequestHandler):
    def get(self, c_page):
        # c_page表示url傳遞過來的當前頁數, len(USER_LIST)表示總共有多少條資料
        pg = Page(c_page, len(USER_LIST))
        #開始頁數
        start = pg.start_page
        #尾頁
        end = pg.end_page
        #當前顯示的資料片段
        current_list = USER_LIST[start:end]
        #傳入index並返回對應的下面分頁部分的html程式碼
        str_page = pg.page_str('index')
        #將當前顯示的資料片段, 當前頁數以及分頁的html程式碼返回給瀏覽器
        self.render('index.html', list_info=current_list, current_page=pg.current_page, str_page=str_page)

    def post(self, c_page):
        #獲取傳入的username的值
        username = self.get_argument('username', None)
        #獲取傳入的email的值
        email = self.get_argument("email", None)
        #生成臨時的字典物件, 表示一個完整的資料片段
        tmp = {'username': username, 'email': email}
        #將該資料片段加入的全域性變數USER_LIST, 這裡用全域性變數模擬資料庫獲取的資料
        USER_LIST.append(tmp)
        self.redirect('/index/' + c_page)複製程式碼

index.html檔案如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .pager a{
            display: inline-block;
            padding: 5px;
            margin: 3px;
            background-color: aquamarine;
        }
        .pager a.active {
            background-color: crimson;
            color: aliceblue;
        }
    </style>
</head>
<body>
<h1>提交資料</h1>
<form method="post" action="/index/{{current_page}}">
    <input name="username" type="text">
    <input name="email" type="text">
    <input type="submit" value="提交">
</form>
<h1>顯示資料</h1>
<table border="1">
    <thead>
    <tr>
        <th>使用者名稱</th>
        <th>郵箱</th>
    </tr>
    </thead>
    <tbody>
    {%for tmp in list_info%}
    <tr>
        <td>{{tmp['username']}}</td>
        <td>{{tmp['email']}}</td>
    </tr>
    {%end%}
    </tbody>
</table>
<div class="pager">
    <!--加raw 以此來直接執行原始的字串, 不做轉義-->
    {%raw str_page%}
</div>
</body>
</html>複製程式碼

start.py檔案如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.web,tornado.ioloop
from controllers import home

if __name__ == '__main__':
    settings = {
        # 模板路徑配置
        'template_path': 'views',
    }

    application = tornado.web.Application([
        (r"/index/(?P<c_page>\d*)", home.IndexHandle),
    ], **settings)
    application.listen(80)
    tornado.ioloop.IOLoop.instance().start()複製程式碼

Tornado框架03-路由系統
執行結果-1

Tornado框架03-路由系統
執行結果-2

Tornado框架03-路由系統
執行結果-3

  • 這種基於正則的分頁實現實際上是在根據url訪問顯示的當前頁數, 在後臺生成當前頁以及當前頁前後5頁的html字串, 然後將這些字串返回給瀏覽器直接渲染顯示

相關文章