Python全栈开发:web框架们
Python的WEB框架
Bottle
Bottle是一個快速、簡潔、輕量級的基于WSIG的微型Web框架,此框架只由一個 .py 文件,除了Python的標(biāo)準(zhǔn)庫外,其不依賴任何其他模塊。
| 1 2 3 4 | pip install bottle easy_install bottle apt-get install python-bottle wget http://bottlepy.org/bottle.py |
Bottle框架大致可以分為以下部分:
- 路由系統(tǒng),將不同請求交由指定函數(shù)處理
- 模板系統(tǒng),將模板中的特殊語法渲染成字符串,值得一說的是Bottle的模板引擎可以任意指定:Bottle內(nèi)置模板、mako、jinja2、cheetah
- 公共組件,用于提供處理請求相關(guān)的信息,如:表單數(shù)據(jù)、cookies、請求頭等
- 服務(wù),Bottle默認支持多種基于WSGI的服務(wù),如:
?
server_names = {'cgi': CGIServer,'flup': FlupFCGIServer,'wsgiref': WSGIRefServer,'waitress': WaitressServer,'cherrypy': CherryPyServer,'paste': PasteServer,'fapws3': FapwsServer,'tornado': TornadoServer,'gae': AppEngineServer,'twisted': TwistedServer,'diesel': DieselServer,'meinheld': MeinheldServer,'gunicorn': GunicornServer,'eventlet': EventletServer,'gevent': GeventServer,'geventSocketIO':GeventSocketIOServer,'rocket': RocketServer,'bjoern' : BjoernServer,'auto': AutoServer, }?
框架的基本使用
| 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) |
一、路由系統(tǒng)
路由系統(tǒng)是的url對應(yīng)指定函數(shù),當(dāng)用戶請求某個url時,就由指定函數(shù)處理當(dāng)前請求,對于Bottle的路由系統(tǒng)可以分為一下幾類:
- 靜態(tài)路由
- 動態(tài)路由
- 請求方法路由
- 二級路由
1、靜態(tài)路由
| 1 2 3 | @root.route('/hello/') def?index(): ????return?template('<b>Hello {{name}}</b>!', name="Alex") |
2、動態(tài)路由
| 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') |
3、請求方法路由
| 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(): ????... |
4、二級路由
#!/usr/bin/env python # -*- coding:utf-8 -*- from bottle import template, Bottleapp01 = Bottle()@app01.route('/hello/', method='GET') def index():return template('<b>App01</b>!')app01.py #!/usr/bin/env python # -*- coding:utf-8 -*- from bottle import template, Bottleapp02 = Bottle()@app02.route('/hello/', method='GET') def index():return template('<b>App02</b>!')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) |
二、模板系統(tǒng)
模板系統(tǒng)用于將Html和自定的值兩者進行渲染,從而得到字符串,然后將該字符串返回給客戶端。我們知道在Bottle中可以使用 內(nèi)置模板系統(tǒng)、mako、jinja2、cheetah等,以內(nèi)置模板系統(tǒng)為例:
<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title> </head> <body><h1>{{name}}</h1> </body> </html>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) |
1、語法
- 單值
- 單行Python代碼
- Python代碼快
- Python、Html混合
?
<h1>1、單值</h1> {{name}}<h1>2、單行Python代碼</h1> % s1 = "hello"<h1>3、Python代碼塊</h1> <%# A block of python codename = name.title().strip()if name == "Alex":name="seven" %><h1>4、Python、Html混合</h1>% if True:<span>{{name}}</span> % end <ul>% for item in name:<li>{{item}}</li>% end </ul>?
2、函數(shù)?
include(sub_template, **variables)
| 1 2 3 4 5 | # 導(dǎo)入其他模板文件 %?include('header.tpl', title='Page Title') Page Content %?include('footer.tpl') |
rebase(name, **variables)
<html> <head><title>{{title or 'No title'}}</title> </head> <body>{{!base}} </body> </html>base.tpl| 1 2 3 4 | # 導(dǎo)入母版 %?rebase('base.tpl', title='Page Title') <p>Page Content ...</p> |
defined(name)
| 1 | # 檢查當(dāng)前變量是否已經(jīng)被定義,已定義True,未定義False |
get(name, default=None)
| 1 | # 獲取某個變量的值,不存在時可設(shè)置默認值 |
setdefault(name, default)
| 1 | # 如果變量不存在時,為變量設(shè)置默認值 |
擴展:自定義函數(shù)
<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title> </head> <body><h1>自定義函數(shù)</h1>{{ wupeiqi() }}</body> </html>hello_template.tpl ?hello_template.tpl ?main.py #!/usr/bin/env python # -*- coding:utf-8 -*- from bottle import template, Bottle,SimpleTemplate root = Bottle()def custom():return '123123'@root.route('/hello/') def index():# 默認情況下去目錄:['./', './views/']中尋找模板文件 hello_template.html# 配置在 bottle.TEMPLATE_PATH 中return template('hello_template.html', name='alex', wupeiqi=custom)root.run(host='localhost', port=8080)main.py注:變量或函數(shù)前添加 【 ! 】,則會關(guān)閉轉(zhuǎn)義的功能
三、公共組件
由于Web框架就是用來【接收用戶請求】-> 【處理用戶請求】-> 【響應(yīng)相關(guān)內(nèi)容】,對于具體如何處理用戶請求,開發(fā)人員根據(jù)用戶請求來進行處理,而對于接收用戶請求和相應(yīng)相關(guān)的內(nèi)容均交給框架本身來處理,其處理完成之后將產(chǎn)出交給開發(fā)人員和用戶。
【接收用戶請求】
當(dāng)框架接收到用戶請求之后,將請求信息封裝在Bottle的request中,以供開發(fā)人員使用
【響應(yīng)相關(guān)內(nèi)容】
當(dāng)開發(fā)人員的代碼處理完用戶請求之后,會將其執(zhí)行內(nèi)容相應(yīng)給用戶,相應(yīng)的內(nèi)容會封裝在Bottle的response中,然后再由框架將內(nèi)容返回給用戶
所以,公共組件本質(zhì)其實就是為開發(fā)人員提供接口,使其能夠獲取用戶信息并配置響應(yīng)內(nèi)容。
1、request
Bottle中的request其實是一個LocalReqeust對象,其中封裝了用戶請求的相關(guān)信息:
request.headers請求頭信息request.queryget請求信息request.formspost請求信息request.files上傳文件信息request.paramsget和post請求信息request.GETget請求信息request.POSTpost和上傳信息request.cookiescookie信息request.environ環(huán)境相關(guān)相關(guān)2、response
Bottle中的request其實是一個LocalResponse對象,其中框架即將返回給用戶的相關(guān)信息:
responseresponse.status_line狀態(tài)行response.status_code狀態(tài)碼response.headers響應(yīng)頭response.charset編碼response.set_cookie在瀏覽器上設(shè)置cookieresponse.delete_cookie在瀏覽器上刪除cookie實例:
from bottle import route, request@route('/login') def login():return '''<form action="/login" method="post">Username: <input name="username" type="text" />Password: <input name="password" type="password" /><input value="Login" type="submit" /></form>'''@route('/login', method='POST') def do_login():username = request.forms.get('username')password = request.forms.get('password')if check_login(username, password):return "<p>Your login information was correct.</p>"else:return "<p>Login failed.</p>"基本Form請求 ?基本Form請求 ?上傳文件? <form action="/upload" method="post" enctype="multipart/form-data">Category: <input type="text" name="category" />Select a file: <input type="file" name="upload" /><input type="submit" value="Start upload" /> </form>@route('/upload', method='POST') def do_upload():category = request.forms.get('category')upload = request.files.get('upload')name, ext = os.path.splitext(upload.filename)if ext not in ('.png','.jpg','.jpeg'):return 'File extension not allowed.'save_path = get_save_path_for_category(category)upload.save(save_path) # appends upload.filename automaticallyreturn 'OK'上傳文件四、服務(wù)
對于Bottle框架其本身未實現(xiàn)類似于Tornado自己基于socket實現(xiàn)Web服務(wù),所以必須依賴WSGI,默認Bottle已經(jīng)實現(xiàn)并且支持的WSGI有:
?WSGI server_names = {'cgi': CGIServer,'flup': FlupFCGIServer,'wsgiref': WSGIRefServer,'waitress': WaitressServer,'cherrypy': CherryPyServer,'paste': PasteServer,'fapws3': FapwsServer,'tornado': TornadoServer,'gae': AppEngineServer,'twisted': TwistedServer,'diesel': DieselServer,'meinheld': MeinheldServer,'gunicorn': GunicornServer,'eventlet': EventletServer,'gevent': GeventServer,'geventSocketIO':GeventSocketIOServer,'rocket': RocketServer,'bjoern' : BjoernServer,'auto': AutoServer, }WSGI使用時,只需在主app執(zhí)行run方法時指定參數(shù)即可:
| 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內(nèi)置模塊wsgiref,如果想要使用其他時,則需要首先安裝相關(guān)類庫,然后才能使用。如:
?bottle.py源碼 # 如果使用Tornado的服務(wù),則需要首先安裝tornado才能使用class TornadoServer(ServerAdapter):""" The super hyped asynchronous server by facebook. Untested. """def run(self, handler): # pragma: no cover# 導(dǎo)入Tornado相關(guān)模塊import tornado.wsgi, tornado.httpserver, tornado.ioloopcontainer = tornado.wsgi.WSGIContainer(handler)server = tornado.httpserver.HTTPServer(container)server.listen(port=self.port,address=self.host)tornado.ioloop.IOLoop.instance().start()bottle.py源碼PS:以上WSGI中提供了19種,如果想要使期支持其他服務(wù),則需要擴展Bottle源碼來自定義一個ServerAdapter
更多參見:http://www.bottlepy.org/docs/dev/index.html
Flask?
Flask是一個基于Python開發(fā)并且依賴jinja2模板和Werkzeug WSGI服務(wù)的一個微型框架,對于Werkzeug本質(zhì)是Socket服務(wù)端,其用于接收http請求并對請求進行預(yù)處理,然后觸發(fā)Flask框架,開發(fā)人員基于Flask框架提供的功能對請求進行相應(yīng)的處理,并返回給用戶,如果要返回給用戶復(fù)雜的內(nèi)容時,需要借助jinja2模板來實現(xiàn)對模板的處理,即:將模板和數(shù)據(jù)進行渲染,將渲染后的字符串返回給用戶瀏覽器。
“微”(micro) 并不表示你需要把整個 Web 應(yīng)用塞進單個 Python 文件(雖然確實可以 ),也不意味著 Flask 在功能上有所欠缺。微框架中的“微”意味著 Flask 旨在保持核心簡單而易于擴展。Flask 不會替你做出太多決策——比如使用何種數(shù)據(jù)庫。而那些 Flask 所選擇的——比如使用何種模板引擎——則很容易替換。除此之外的一切都由可由你掌握。如此,Flask 可以與您珠聯(lián)璧合。
默認情況下,Flask 不包含數(shù)據(jù)庫抽象層、表單驗證,或是其它任何已有多種庫可以勝任的功能。然而,Flask 支持用擴展來給應(yīng)用添加這些功能,如同是 Flask 本身實現(xiàn)的一樣。眾多的擴展提供了數(shù)據(jù)庫集成、表單驗證、上傳處理、各種各樣的開放認證技術(shù)等功能。Flask 也許是“微小”的,但它已準(zhǔn)備好在需求繁雜的生產(chǎn)環(huán)境中投入使用。
安裝
| 1 | pip install Flask |
一、第一次
| 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() |
二、路由系統(tǒng)
- @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'])
常用路由系統(tǒng)有以上五種,所有的路由系統(tǒng)都是基于一下對應(yīng)關(guān)系來處理:
| 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默認不支持直接寫正則表達式的路由,不過可以通過自定義來實現(xiàn),見:https://segmentfault.com/q/1010000000125259
三、模板
1、模板的使用
Flask使用的是Jinja2模板,所以其語法和Django無差別
2、自定義模板方法
Flask中自定義模板方法的方式和Bottle相似,創(chuàng)建一個函數(shù)并通過參數(shù)的形式傳入render_template,如:
<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title> </head> <body><h1>自定義函數(shù)</h1>{{ww()|safe}}</body> </html>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() |
四、公共組件
1、請求
對于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 |
2、響應(yīng)
當(dāng)用戶請求被開發(fā)人員的邏輯處理完成之后,會將結(jié)果發(fā)送給用戶瀏覽器,那么就需要對請求做出相應(yīng)的響應(yīng)。
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.錯誤頁面
from flask import Flask, abort, render_template app = Flask(__name__)@app.route('/e1/', methods=['GET', 'POST']) def index():abort(404, 'Nothing') app.run()指定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.設(shè)置相應(yīng)信息
使用make_response可以對相應(yīng)的內(nèi)容進行操作
| 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() |
3、Session
除請求對象之外,還有一個 session 對象。它允許你在不同請求間存儲特定用戶的信息。它是在 Cookies 的基礎(chǔ)上實現(xiàn)的,并且對 Cookies 進行密鑰簽名要使用會話,你需要設(shè)置一個密鑰。
-
設(shè)置: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' |
4.message
message是一個基于Session實現(xiàn)的用于保存數(shù)據(jù)的集合,其特點是:使用一次就刪除
?index.html| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from?flask?import?Flask, flash, redirect, render_template, request app?=?Flask(__name__) app.secret_key?=?'some_secret' @app.route('/') def?index1(): ????return?render_template('index.html') @app.route('/set') def?index2(): ????v?=?request.args.get('p') ????flash(v) ????return?'ok' if?__name__?==?"__main__": ????app.run() |
5.中間件
| 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 | from?flask?import?Flask, flash, redirect, render_template, request app?=?Flask(__name__) app.secret_key?=?'some_secret' @app.route('/') def?index1(): ????return?render_template('index.html') @app.route('/set') def?index2(): ????v?=?request.args.get('p') ????flash(v) ????return?'ok' class?MiddleWare: ????def?__init__(self,wsgi_app): ????????self.wsgi_app?=?wsgi_app ????def?__call__(self,?*args,?**kwargs): ????????return?self.wsgi_app(*args,?**kwargs) if?__name__?==?"__main__": ????app.wsgi_app?=?MiddleWare(app.wsgi_app) ????app.run(port=9999) |
Flask還有眾多其他功能,更多參見:
? ? http://docs.jinkan.org/docs/flask/
? ??http://flask.pocoo.org/
轉(zhuǎn)載于:https://www.cnblogs.com/nixingguo/p/6613584.html
總結(jié)
以上是生活随笔為你收集整理的Python全栈开发:web框架们的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 20155302 2016-2017-2
- 下一篇: python-变量操作-字符串