python--第二十一/二天总结

Python的WEB框架html

Bottle

Bottle是一个快速、简洁、轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Python的标准库外,其不依赖任何其余模块。python

1
2
3
4
pip install bottle
easy_install bottle
apt - get install python - bottle
wget http: / / bottlepy.org / bottle.py

Bottle框架大体能够分为如下部分:git

  • 路由系统,将不一样请求交由指定函数处理
  • 模板系统,将模板中的特殊语法渲染成字符串,值得一说的是Bottle的模板引擎能够任意指定:Bottle内置模板、makojinja2cheetah
  • 公共组件,用于提供处理请求相关的信息,如:表单数据、cookies、请求头等
  • 服务,Bottle默认支持多种基于WSGI的服务,如:

框架的基本使用程序员

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from bottle import template, Bottle
root = Bottle()
 
@root .route( '/hello/' )
def index():
     return "Hello World"
     # return template('<b>Hello {{name}}</b>!', name="Alex")
 
root.run(host = 'localhost' , port = 8080 )

1、路由系统github

路由系统是的url对应指定函数,当用户请求某个url时,就由指定函数处理当前请求,对于Bottle的路由系统能够分为一下几类:web

  • 静态路由
  • 动态路由
  • 请求方法路由
  • 二级路由

一、静态路由正则表达式

1
2
3
@root .route( '/hello/' )
def index():
     return template( '<b>Hello {{name}}</b>!' , name = "Alex" )

二、动态路由算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@root .route( '/wiki/<pagename>' )
def callback(pagename):
     ...
 
@root .route( '/object/<id:int>' )
def callback( id ):
     ...
 
@root .route( '/show/<name:re:[a-z]+>' )
def callback(name):
     ...
 
@root .route( '/static/<path:path>' )
def callback(path):
     return static_file(path, root = 'static' )

三、请求方法路由数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@root .route( '/hello/' , method = 'POST' )
def index():
     ...
 
@root .get( '/hello/' )
def index():
     ...
 
@root .post( '/hello/' )
def index():
     ...
 
@root .put( '/hello/' )
def index():
     ...
 
@root .delete( '/hello/' )
def index():
     ...

四、二级路由django

app01.py
app02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from bottle import template, Bottle
from bottle import static_file
root = Bottle()
 
@root .route( '/hello/' )
def index():
     return template( '<b>Root {{name}}</b>!' , name = "Alex" )
 
from framwork_bottle import app01
from framwork_bottle import app02
 
root.mount( 'app01' , app01.app01)
root.mount( 'app02' , app02.app02)
 
root.run(host = 'localhost' , port = 8080 )

2、模板系统

模板系统用于将Html和自定的值二者进行渲染,从而获得字符串,而后将该字符串返回给客户端。咱们知道在Bottle中可使用 内置模板系统、makojinja2cheetah等,之内置模板系统为例:

hello_template.tpl
1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from bottle import template, Bottle
root = Bottle()
 
@root .route( '/hello/' )
def index():
     # 默认状况下去目录:['./', './views/']中寻找模板文件 hello_template.html
     # 配置在 bottle.TEMPLATE_PATH 中
     return template( 'hello_template.tpl' , name = 'alex' )
 
root.run(host = 'localhost' , port = 8080 )

一、语法

  • 单值
  • 单行Python代码
  • Python代码快
  • Python、Html混合

二、函数 

include(sub_template, **variables)

1
2
3
4
5
# 导入其余模板文件
 
% include( 'header.tpl' , title = 'Page Title' )
Page Content
% include( 'footer.tpl' )

rebase(name, **variables)

base.tpl
1
2
3
4
# 导入母版
 
% rebase( 'base.tpl' , title = 'Page Title' )
<p>Page Content ...< / p>

defined(name)

1
# 检查当前变量是否已经被定义,已定义True,未定义False

get(name, default=None)

1
# 获取某个变量的值,不存在时可设置默认值

setdefault(name, default)

1
# 若是变量不存在时,为变量设置默认值

扩展:自定义函数

hello_template.tpl
main.py

注:变量或函数前添加 【 ! 】,则会关闭转义的功能

3、公共组件

因为Web框架就是用来【接收用户请求】-> 【处理用户请求】-> 【响应相关内容】,对于具体如何处理用户请求,开发人员根据用户请求来进行处理,而对于接收用户请求和相应相关的内容均交给框架自己来处理,其处理完成以后将产出交给开发人员和用户。

【接收用户请求】

当框架接收到用户请求以后,将请求信息封装在Bottle的request中,以供开发人员使用

【响应相关内容】

当开发人员的代码处理完用户请求以后,会将其执行内容相应给用户,相应的内容会封装在Bottle的response中,而后再由框架将内容返回给用户

因此,公共组件本质其实就是为开发人员提供接口,使其可以获取用户信息并配置响应内容。

一、request

Bottle中的request实际上是一个LocalReqeust对象,其中封装了用户请求的相关信息:

二、response

Bottle中的request实际上是一个LocalResponse对象,其中框架即将返回给用户的相关信息:

实例:

基本Form请求
上传文件 

4、服务

对于Bottle框架其自己未实现相似于Tornado本身基于socket实现Web服务,因此必须依赖WSGI,默认Bottle已经实现而且支持的WSGI有:

WSGI

使用时,只需在主app执行run方法时指定参数便可:

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from bottle import Bottle
root = Bottle()
 
@root .route( '/hello/' )
def index():
     return "Hello World"
# 默认server ='wsgiref'
root.run(host = 'localhost' , port = 8080 , server = 'wsgiref' )

默认server="wsgiref",即:使用Python内置模块wsgiref,若是想要使用其余时,则须要首先安装相关类库,而后才能使用。如:

bottle.py源码

PS:以上WSGI中提供了19种,若是想要使期支持其余服务,则须要扩展Bottle源码来自定义一个ServerAdapter

更多参见:http://www.bottlepy.org/docs/dev/index.html

Flask 

Flask是一个基于Python开发而且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,而后触发Flask框架,开发 人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,若是要返回给用户复杂的内容时,须要借助jinja2模板来实现对模板的处理, 即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。

“微”(micro) 并不表示你须要把整个 Web 应用塞进单个 Python 文件(虽然确实能够 ),也不意味着 Flask 在功能上有所欠缺。微框架中的“微”意味着 Flask 旨在保持核心简单而易于扩展。Flask 不会替你作出太多决策——好比使用何种数据库。而那些 Flask 所选择的——好比使用何种模板引擎——则很容易替换。除此以外的一切都由可由你掌握。如此,Flask 能够与您珠联璧合。

默认状况下,Flask 不包含数据库抽象层、表单验证,或是其它任何已有多种库能够胜任的功能。然而,Flask 支持用扩展来给应用添加这些功能,如同是 Flask 自己实现的同样。众多的扩展提供了数据库集成、表单验证、上传处理、各类各样的开放认证技术等功能。Flask 也许是“微小”的,但它已准备好在需求繁杂的生产环境中投入使用。

安装

1
pip install Flask
werkzeug

1、第一次

1
2
3
4
5
6
7
8
9
from flask import Flask
app = Flask(__name__)
 
@app .route( "/" )
def hello():
     return "Hello World!"
 
if __name__ = = "__main__" :
     app.run()

2、路由系统

  • @app.route('/user/<username>')
  • @app.route('/post/<int:post_id>')
  • @app.route('/post/<float:post_id>')
  • @app.route('/post/<path:path>')
  • @app.route('/login', methods=['GET', 'POST'])

经常使用路由系统有以上五种,全部的路由系统都是基于一下对应关系来处理:

1
2
3
4
5
6
7
8
9
DEFAULT_CONVERTERS = {
     'default' :          UnicodeConverter,
     'string' :           UnicodeConverter,
     'any' :              AnyConverter,
     'path' :             PathConverter,
     'int' :              IntegerConverter,
     'float' :            FloatConverter,
     'uuid' :             UUIDConverter,
}

注:对于Flask默认不支持直接写正则表达式的路由,不过能够经过自定义来实现,见:https://segmentfault.com/q/1010000000125259

3、模板

一、模板的使用

Flask使用的是Jinja2模板,因此其语法和Django无差异

二、自定义模板方法

Flask中自定义模板方法的方式和Bottle类似,建立一个函数并经过参数的形式传入render_template,如:

index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask,render_template
app = Flask(__name__)
 
 
def wupeiqi():
     return '<h1>Wupeiqi</h1>'
 
@app .route( '/login' , methods = [ 'GET' , 'POST' ])
def login():
     return render_template( 'login.html' , ww = wupeiqi)
 
app.run()

4、公共组件

一、请求

对于Http请求,Flask会讲请求信息封装在request中(werkzeug.wrappers.BaseRequest),提供的以下经常使用方法和字段以供使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
request.method
request.args
request.form
request.values
request.files
request.cookies
request.headers
request.path
request.full_path
request.script_root
request.url
request.base_url
request.url_root
request.host_url
request.host
表单处理Demo
上传文件Demo
Cookie操做

二、响应

当用户请求被开发人员的逻辑处理完成以后,会将结果发送给用户浏览器,那么就须要对请求作出相应的响应。

a.字符串

1
2
3
@app .route( '/index/' , methods = [ 'GET' , 'POST' ])
def index():
     return "index"

b.模板引擎

1
2
3
4
5
6
7
8
from flask import Flask,render_template,request
app = Flask(__name__)
 
@app .route( '/index/' , methods = [ 'GET' , 'POST' ])
def index():
     return render_template( "index.html" )
 
app.run()

c.重定向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, redirect, url_for
app = Flask(__name__)
 
@app .route( '/index/' , methods = [ 'GET' , 'POST' ])
def index():
     # return redirect('/login/')
     return redirect(url_for( 'login' ))
 
@app .route( '/login/' , methods = [ 'GET' , 'POST' ])
def login():
     return "LOGIN"
 
app.run()

d.错误页面

指定URL,简单错误
1
2
3
4
5
6
7
8
9
10
11
12
from flask import Flask, abort, render_template
app = Flask(__name__)
 
@app .route( '/index/' , methods = [ 'GET' , 'POST' ])
def index():
     return "OK"
 
@app .errorhandler( 404 )
def page_not_found(error):
     return render_template( 'page_not_found.html' ), 404
 
app.run()

e.设置相应信息

使用make_response能够对相应的内容进行操做

1
2
3
4
5
6
7
8
9
10
11
12
13
from flask import Flask, abort, render_template,make_response
app = Flask(__name__)
 
@app .route( '/index/' , methods = [ 'GET' , 'POST' ])
def index():
     response = make_response(render_template( 'index.html' ))
     # response是flask.wrappers.Response类型
     # response.delete_cookie
     # response.set_cookie
     # response.headers['X-Something'] = 'A value'
     return response
 
app.run()

三、Session

除请求对象以外,还有一个 session 对象。它容许你在不一样请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,而且对 Cookies 进行密钥签名要使用会话,你须要设置一个密钥。

  • 设置:session['username'] = 'xxx'

  • 删除:session.pop('username', None)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from flask import Flask, session, redirect, url_for, escape, request
 
app = Flask(__name__)
 
@app .route( '/' )
def index():
     if 'username' in session:
         return 'Logged in as %s' % escape(session[ 'username' ])
     return 'You are not logged in'
 
@app .route( '/login' , methods = [ 'GET' , 'POST' ])
def login():
     if request.method = = 'POST' :
         session[ 'username' ] = request.form[ 'username' ]
         return redirect(url_for( 'index' ))
     return '''
         <form action="" method="post">
             <p><input type=text name=username>
             <p><input type=submit value=Login>
         </form>
     '''
 
@app .route( '/logout' )
def logout():
     # remove the username from the session if it's there
     session.pop( 'username' , None )
     return redirect(url_for( 'index' ))
 
# set the secret key.  keep this really secret:
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'

Flask还有众多其余功能,更多参见:
    http://docs.jinkan.org/docs/flask/
    http://flask.pocoo.org/

Tornado

Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本。这个 Web 框架看起来有些像web.py 或者 Google 的 webapp,不过为了能有效利用非阻塞式服务器环境,这个 Web 框架还包含了一些相关的有用工具 和优化。

Tornado 和如今的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,并且速度至关快。得利于其 非阻塞的方式和对 epoll 的 运用,Tornado 每秒能够处理数以千计的链接,这意味着对于实时 Web 服务来讲,Tornado 是一个理想的 Web 框架。咱们开发这个 Web 服务器的主要目的就是为了处理 FriendFeed 的实时功能 ——在 FriendFeed 的应用里每个活动用户都会保持着一个服务器链接。(关于如何扩容 服务器,以处理数以千计的客户端的链接的问题,请参阅 C10K problem。)

1
2
3
pip install tornado
源码安装
     https: / / pypi.python.org / packages / source / t / tornado / tornado - 4.3 .tar.gz

1、快速上手

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python
# -*- coding:utf-8 -*-
  
import tornado.ioloop
import tornado.web
  
  
class MainHandler(tornado.web.RequestHandler):
     def get( self ):
         self .write( "Hello, world" )
  
application = tornado.web.Application([
     (r "/index" , MainHandler),
])
  
  
if __name__ = = "__main__" :
     application.listen( 8888 )
     tornado.ioloop.IOLoop.instance().start()

第一步:执行脚本,监听 8888 端口

第二步:浏览器客户端访问 /index  -->  http://127.0.0.1:8888/index

第三步:服务器接受请求,并交由对应的类处理该请求

第四步:类接受到请求以后,根据请求方式(post / get / delete ...)的不一样调用并执行相应的方法

第五步:方法返回值的字符串内容发送浏览器

异步非阻塞实例

2、路由系统

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/env python
# -*- coding:utf-8 -*-
  
import tornado.ioloop
import tornado.web
  
  
class MainHandler(tornado.web.RequestHandler):
     def get( self ):
         self .write( "Hello, world" )
  
class StoryHandler(tornado.web.RequestHandler):
     def get( self , story_id):
         self .write( "You requested the story " + story_id)
  
class BuyHandler(tornado.web.RequestHandler):
     def get( self ):
         self .write( "buy.wupeiqi.com/index" )
  
application = tornado.web.Application([
     (r "/index" , MainHandler),
     (r "/story/([0-9]+)" , StoryHandler),
])
  
application.add_handlers( 'buy.wupeiqi.com$' , [
     (r '/index' ,BuyHandler),
])
  
if __name__ = = "__main__" :
     application.listen( 80 )
     tornado.ioloop.IOLoop.instance().start()

3、模板

Tornao中的模板语言和django中相似,模板引擎将模板文件载入内存,而后将数据嵌入其中,最终获取到一个完整的字符串,再将字符串返回给请求者。

Tornado 的模板支持“控制语句”和“表达语句”,控制语句是使用 {% 和 %} 包起来的 例如 {% if len(items) > 2 %}。表达语句是使用 {{ 和 }} 包起来的,例如 {{ items[0] }}

控制语句和对应的 Python 语句的格式基本彻底相同。咱们支持 ifforwhile 和 try,这些语句逻辑结束的位置须要用 {% end %} 作标记。还经过 extends 和 block 语句实现了模板继承。这些在 template 模块 的代码文档中有着详细的描述。

layout.html
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python
# -*- coding:utf-8 -*-
  
import tornado.ioloop
import tornado.web
  
  
class MainHandler(tornado.web.RequestHandler):
     def get( self ):
         self .render( 'home/index.html' )
  
settings = {
     'template_path' : 'template' ,
}
  
application = tornado.web.Application([
     (r "/index" , MainHandler),
], * * settings)
  
  
if __name__ = = "__main__" :
     application.listen( 80 )
     tornado.ioloop.IOLoop.instance().start()

在模板中默认提供了一些函数、字段、类以供模板使用:

  • escapetornado.escape.xhtml_escape 的別名
  • xhtml_escapetornado.escape.xhtml_escape 的別名
  • url_escapetornado.escape.url_escape 的別名
  • json_encodetornado.escape.json_encode 的別名
  • squeezetornado.escape.squeeze 的別名
  • linkifytornado.escape.linkify 的別名
  • datetime: Python 的 datetime 模组
  • handler: 当前的 RequestHandler 对象
  • requesthandler.request 的別名
  • current_userhandler.current_user 的別名
  • localehandler.locale 的別名
  • _handler.locale.translate 的別名
  • static_url: for handler.static_url 的別名
  • xsrf_form_htmlhandler.xsrf_form_html 的別名

Tornado默认提供的这些功能其实本质上就是 UIMethod 和 UIModule,咱们也能够自定义从而实现相似于Django的simple_tag的功能:
一、定义

uimethods.py
uimodules.py

二、注册

main.py

三、使用

index.html

4、实用功能

一、静态文件

对于静态文件,能够配置静态文件的目录和前段使用时的前缀,而且Tornaodo还支持静态文件缓存。

main.py
index.html

备注:静态文件缓存的实现

静态文件缓存源码

二、csrf

Tornado中的夸张请求伪造和Django中的类似,跨站伪造请求(Cross-site request forgery)

配置
普通表单使用
Ajax使用

注:Ajax使用时,本质上就是去获取本地的cookie,携带cookie再来发送请求

三、cookie

Tornado中能够对cookie进行操做,而且还能够对cookie进行签名以放置伪造。

a、基本操做

Code

b、签名

Cookie 很容易被恶意的客户端伪造。加入你想在 cookie 中保存当前登录用户的 id 之类的信息,你须要对 cookie 做签名以防止伪造。Tornado 经过 set_secure_cookie 和 get_secure_cookie 方法直接支持了这种功能。 要使用这些方法,你须要在建立应用时提供一个密钥,名字为 cookie_secret。 你能够把它做为一个关键词参数传入应用的设置中:

Code
内部算法
内部算法-加密
内部算法-解密

签名Cookie的本质是:

写cookie过程:

  • 将值进行base64加密
  • 对除值之外的内容进行签名,哈希算法(没法逆向解析)
  • 拼接 签名 + 加密值

读cookie过程:

  • 读取 签名 + 加密值
  • 对签名进行验证
  • base64解密,获取值内容

注:许多API验证机制和安全cookie的实现机制相同。

Demo-基于cookie进行用户验证
Demo-Toando内部提供基于cookie进行用户验证

5、扩展功能

一、自定义Session

a.知识储备

b.session实现机制

c. Session框架

一致性哈希
Session

二、自定义模型版定

模型绑定有两个主要功能:

  • 自动生成html表单
  • 用户输入验证

在以前学习的Django中为程序员提供了很是便捷的模型绑定功能,可是在Tornado中,一切须要本身动手!!!

html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/usr/bin/env python
# -*- coding:utf-8 -*-
  
import tornado.ioloop
import tornado.web
from hashlib import sha1
import os, time
import re
  
  
class MainForm( object ):
     def __init__( self ):
         self .host = "(.*)"
         self .ip = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$"
         self .port = '(\d+)'
         self .phone = '^1[3|4|5|8][0-9]\d{8}$'
  
     def check_valid( self , request):
         form_dict = self .__dict__
         for key, regular in form_dict.items():
             post_value = request.get_argument(key)
             # 让提交的数据 和 定义的正则表达式进行匹配
             ret = re.match(regular, post_value)
             print key,ret,post_value
  
  
class MainHandler(tornado.web.RequestHandler):
     def get( self ):
         self .render( 'index.html' )
     def post( self , * args, * * kwargs):
         obj = MainForm()
         result = obj.check_valid( self )
         self .write( 'ok' )
  
  
  
settings = {
     'template_path' : 'template' ,
     'static_path' : 'static' ,
     'static_url_prefix' : '/static/' ,
     'cookie_secret' : 'aiuasdhflashjdfoiuashdfiuh' ,
     'login_url' : '/login'
}
  
application = tornado.web.Application([
     (r "/index" , MainHandler),
], * * settings)
  
  
if __name__ = = "__main__" :
     application.listen( 8888 )
     tornado.ioloop.IOLoop.instance().start()

因为请求的验证时,须要考虑是否能够为空以及正则表达式的复用,因此:

Form验证框架
相关文章
相关标签/搜索