[Python笔记]第十六篇:web框架之Tornado

Tornado是一个基于python的web框架,xxxxx

 安装

python -m pip install tornado

第一个Tornado程序

 安装完毕我们就可以新建一个app.py文件,放入下面的代码直接运行就可以了,然后在浏览器访问127.0.0.1:8888

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执行过程:

  • 第一步:执行脚本,监听 8888 端口
  • 第二步:浏览器客户端访问 /index  -->  http://127.0.0.1:8888/index
  • 第三步:服务器接受请求,并交由对应的类处理该请求
  • 第四步:类接受到请求之后,根据请求方式(post / get / delete ...)的不同调用并执行相应的方法
  • 第五步:方法返回值的字符串内容发送浏览器

路由系统

路由系统执行过程是:

用户访问一个指定url(如:www.abc.org/index)   ---->  路由系统去匹配url找到Handler  ---->  Handler处理用户请求(get/post)

路由系统其实就是 url 和 类 的对应关系,这里不同于其他框架,其他很多框架均是 url 对应 函数,Tornado中每个url对应的是一个类。

顺带提一句,Tornado自己基于socket实现Web服务,Django等需要依赖其他的wsgi

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中原生支持二级域名的路由,如:

 模板引擎

Tornao中的模板语言和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;  312px; margin-top: 20px; margin-bottom: 20px;">
                    <img src="/static/pic/top24.png">
                </div>
                <div style="height: 200px;  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我们将在下一篇博文里面继续探讨

原文地址:https://www.cnblogs.com/yaohan/p/5717819.html