[Python筆記]第十六篇:web框架之Tornado

Tornado是一個基於python的web框架,xxxxxjavascript

 安裝

python -m pip install tornadocss

第一個Tornado程序

 安裝完畢咱們就能夠新建一個app.py文件,放入下面的代碼直接運行就能夠了,而後在瀏覽器訪問127.0.0.1:8888html

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

application = tornado.web.Application([
    (r"/", MainHandler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

 tornado執行過程:java

  • 第一步:執行腳本,監聽 8888 端口
  • 第二步:瀏覽器客戶端訪問 /index  -->  http://127.0.0.1:8888/index
  • 第三步:服務器接受請求,並交由對應的類處理該請求
  • 第四步:類接受到請求以後,根據請求方式(post / get / delete ...)的不一樣調用並執行相應的方法
  • 第五步:方法返回值的字符串內容發送瀏覽器

路由系統

路由系統執行過程是:python

用戶訪問一個指定url(如:www.abc.org/index)   ---->  路由系統去匹配url找到Handler  ---->  Handler處理用戶請求(get/post)git

路由系統其實就是 url 和 類 的對應關係,這裏不一樣於其餘框架,其餘不少框架均是 url 對應 函數,Tornado中每一個url對應的是一個類。github

順帶提一句,Tornado本身基於socket實現Web服務,Django等須要依賴其餘的wsgiweb

import tornado.web

settings = {
    'template_path': 'views',
    'static_path': 'static',
}


class IndexHandler(tornado.web.RequestHandler):
    def get(self,page=None):
        pass
    
    def post(self, *args, **kwargs):
        pass


application = tornado.web.Application([
    (r"/", IndexHandler),
    (r"/index/", IndexHandler),
], **settings)


if __name__ == "__main__":
    application.listen(8000)
    tornado.ioloop.IOLoop.instance().start()
View Code

 Tornado中原生支持二級域名的路由,如:ajax

 模板引擎

Tornao中的模板語言和django中相似,模板引擎將模板文件載入內存,而後將數據嵌入其中,最終獲取到一個完整的字符串,再將字符串返回給請求者。django

Tornado 的模板支持「控制語句」和「表達語句」,控制語句是使用 {% 和 %} 包起來的 例如 {% if len(items) > 2 %}。表達語句是使用 {{ 和 }} 包起來的,例如 {{ items[0] }}

控制語句和對應的 Python 語句的格式基本徹底相同。咱們支持 ifforwhile 和 try,這些語句邏輯結束的位置須要用 {% end %} 作標記。還經過 extends 和 block 語句實現了模板繼承。這些在 template 模塊 的代碼文檔中有着詳細的描述。

在模板中默認提供了一些函數、字段、類以供模板使用:

escape: tornado.escape.xhtml_escape 的別名
xhtml_escape: tornado.escape.xhtml_escape 的別名
url_escape: tornado.escape.url_escape 的別名
json_encode: tornado.escape.json_encode 的別名
squeeze: tornado.escape.squeeze 的別名
linkify: tornado.escape.linkify 的別名
datetime: Python 的 datetime 模組
handler: 當前的 RequestHandler 對象
request: handler.request 的別名
current_user: handler.current_user 的別名
locale: handler.locale 的別名
_: handler.locale.translate 的別名
static_url: for handler.static_url 的別名
xsrf_form_html: handler.xsrf_form_html 的別名

Tornado默認提供的這些功能其實本質上就是 UIMethod 和 UIModule,咱們也能夠自定義從而實現相似於Django的simple_tag的功能:

母板

1.定義

 

母板完整代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>抽屜新熱榜-聚合每日熱門、搞笑、有趣資訊</title>
    <link type="text/css" rel="stylesheet" href="{{ static_url('css/common.css') }}" />
    <!--<link rel="stylesheet" href='{{static_url("plugins/bootstrap3/css/bootstrap.css") }}' />-->
</head>
<body>
    <div class="top">
        <div class="top-content">
            <img class="logo" src="/static/pic/logo.png">
            <div class="action-menu">
                <ul class="nav-ul">
                    <li class="nav-li"><a href="/">所有</a></li>
                    <li class="nav-li"><a>42區</a></li>
                    <li class="nav-li"><a>段子</a></li>
                    <li class="nav-li"><a>圖片</a></li>
                    <li class="nav-li"><a>挨踢1024</a></li>
                    <li class="nav-li"><a>你問我答</a></li>
                </ul>
            </div>
            <div class="search-ground">
                <span class="search-ico"></span>
            </div>
            <div>
                <form action="https://www.sogou.com/qurey" name="qurey" method="get">
                    <input type="text" class="search-box">
                </form>
            </div>
            <div>
                {% if user_info["is_login"] %}
                    <div class="nav-2">
                        <a style="text-decoration: none;color: white" href="/user/link/saved/1" id="loginUserNc" class="userPro-Box" style="color: white">
                            <img src="http://img2.chouti.com/CHOUTI_05B313F703D34646848BCC5571510683_W148H148=30x30).jpg" id="userProImg">
                            <span class="u-nick" id="userProNick">{{user_info["username"]}}</span>
                            <em id="userProArr"></em>
                        </a>
                        <div class="nav-2"><a style="color: #d9edf7" href="/logout">退出</a></div>
                    </div>
                {% else %}
                    <div class="nav-2"><a href="/login">登陸</a></div>
                    <div class="nav-2"><a href="/reg">註冊</a></div>
                {% end %}
            </div>





        </div>
    </div>
    <div class="background">
        <div class="main-content">
                {% block middle %}{% end %}
            <div class="footer">
                <div class="footer-item">
                    <hr>
                    <a >關於咱們</a>
                    <span>|</span>
                    <a>聯繫咱們</a>
                    <span>|</span>
                    <a>服務條款</a>
                    <span>|</span>
                    <a>隱私政策</a>
                    <span>|</span>
                    <a>抽屜新熱榜工具</a>
                    <span>|</span>
                    <a>下載客戶端</a>
                    <span>|</span>
                    <a>意見與反饋</a>
                    <span>|</span>
                    <a>友情連接</a>
                    <span>|</span>
                    <a>公告</a>
                    <span>|</span>
                    <img src="http://dig.chouti.com/images/ct_rss.gif">
                </div>
                <div class="footer-item2">
                    <a target="_blank" href="http://www.gozap.com/"><img class="foot_e" src="http://dig.chouti.com/images/gozap-logo-50_15.gif"></a>
                    <span class="foot_d">旗下站點</span>
                    <span class="foot_a">&copy; 2016 chouti.com</span>
                    <a target="_blank" href="http://www.miibeian.gov.cn/" class="foot_b">京ICP備09053974號-3 京公網安備 110102004562</a>
                    <div style="margin-top:6px; text-align: center">版權全部:北京格致璞科技有限公司</div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>
View Code

2.使用

 

子板完整代碼

{% extends '../master/layout.html' %}

{% block middle %}
<div class="left">
    <div class="nav-top-area">
        <div class="child-nav">
            <div class="hotbtn">
                <a href="/all/hot/recent/1" hidefocus="false" >最熱</a>
            </div>
            <div class="newbtn">
                <a href="/all/new/1" hidefocus="false" >最新</a>
            </div>
            <div class="personbtn">
                <a href="/all/man/1" hidefocus="false" >人類發佈</a>
            </div>
        </div>

        <div href="javascript:;" class="publish-btn">
            <!--<a class="ico n1"></a><a class="n2">發佈</a>-->
            <a class="publish-icon" href="/publish">發佈</a>
        </div>

        <div class="sort-nav">
            <a href="/all/hot/recent/1" hidefocus="false" class="active hotbtn" style="color: #b4b4b4;">即時排序</a>
            <a href="/all/hot/24hr/1" hidefocus="false" class="newbtn" style="color: #390;;">24小時</a>
            <a href="/all/hot/72hr/1" hidefocus="false" class="newbtn" style="color: #390;;">3天</a>
        </div>
    </div>
    <div class="content-list">
    {% for new in news_list %}
        <div class="item">
            <div class="news-pic">
                <img src="{{new['post_img']}}">
            </div>
            <div class="part1">
                <a>{{new['post_title']}}</a>
                <span>douban.com</span>
                <span>42區</span>
            </div>
            <div class="part2">
                <span>{{new['post_content']}}</span>
            </div>
        </div>
    {% end %}
    </div>
    <div class="pager">
        <!--阻止轉義-->
        {% raw str_page %}
    </div>
</div>
<div class="right">
                <div class="chat-area">
                    <img src="/static/pic/chouti-chat.png">
                </div>
                <div style="height: 581px; width: 312px; margin-top: 20px; margin-bottom: 20px;">
                    <img src="/static/pic/top24.png">
                </div>
                <div style="height: 200px; width: 300px">
                    <img src="/static/pic/ad_c155.jpg">
                </div>
            </div>
{% end %}
View Code

3.include

include能夠吧經常使用的小部件如登陸框寫在一個html文件裏

讓其餘頁面直接調用,提升代碼的複用性

一個網頁既調用母板 內部內容直接調用include的例子:

{% extends '../master/layout.html' %}
{% block middle %}
    {% include '../include/login.html' %}
{% end %}

 

4.模板語言裏的if判斷和for循環

for循環

對於Handler裏面post或者get方法裏面render時候傳入一個news_list的字典

模板語言循環解析他

例子:

    <div class="content-list">
    {% for new in news_list %}
        <div class="item">
            <div class="news-pic">
                <img src="{{new['post_img']}}">
            </div>
            <div class="part1">
                <a>{{new['post_title']}}</a>
                <span>douban.com</span>
                <span>42區</span>
            </div>
            <div class="part2">
                <span>{{new['post_content']}}</span>
            </div>
        </div>
    {% end %}
    </div>
View Code

 

if判斷

能夠根據接收到的判斷顯示仍是不顯示某個html代碼塊

例子:

<div>
    {% if user_info["is_login"] %}
        <div class="nav-2">
            <a style="text-decoration: none;color: white" href="/user/link/saved/1" id="loginUserNc" class="userPro-Box" style="color: white">
                <img src="http://img2.chouti.com/CHOUTI_05B3131510683_W148H148=30x30).jpg" id="userProImg">
                <span class="u-nick" id="userProNick">{{user_info["username"]}}</span>
                <em id="userProArr"></em>
            </a>
            <div class="nav-2"><a style="color: #d9edf7" href="/logout">退出</a></div>
        </div>
    {% else %}
        <div class="nav-2"><a href="/login">登陸</a></div>
        <div class="nav-2"><a href="/reg">註冊</a></div>
    {% end %}
</div>
View Code

 

 自定義UIMethod以UIModule

a.定義

# uimethods.py
 
def tab(self):
    return 'UIMethod'
uimethods.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from tornado.web import UIModule
from tornado import escape

class custom(UIModule):

    def render(self, *args, **kwargs):
        return escape.xhtml_escape('<h1>wupeiqi</h1>')
        #return escape.xhtml_escape('<h1>wupeiqi</h1>')

uimodules.py
uimodules.py

b.註冊

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

import tornado.ioloop
import tornado.web
from tornado.escape import linkify
import uimodules as md
import uimethods as mt

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('index.html')

settings = {
    'template_path': 'template',
    'static_path': 'static',
    'static_url_prefix': '/static/',
    'ui_methods': mt,
    'ui_modules': md,
}

application = tornado.web.Application([
    (r"/index", MainHandler),
], **settings)


if __name__ == "__main__":
    application.listen(8009)
    tornado.ioloop.IOLoop.instance().start()
View Code

c.使用

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <link href="{{static_url("commons.css")}}" rel="stylesheet" />
</head>
<body>
    <h1>hello</h1>
    {% module custom(123) %}
    {{ tab() }}
</body>
View Code

 

 

附:一個比較規範的Tornado project layout

 

有關cookie,session,驗證碼,表單驗證,csrf,xss,ajax咱們將在下一篇博文裏面繼續探討

相關文章
相關標籤/搜索