本章將開始熟悉一個最基本的Flask應(yīng)用的不同部分,并自己動手構(gòu)建一個Flask Web應(yīng)用。
初始化
所有Flask的應(yīng)用程序必須構(gòu)建一個Flask的對象,然后通過協(xié)議將從客戶端收到的所有請求交給這個實(shí)例進(jìn)行處理:
from flask import Flask
Flask app = Flask(__name__)
關(guān)于Flask中參數(shù)的說明:Flask的構(gòu)造函數(shù)只接收一個參數(shù),這里是__name__會指向該程序片段所在的模塊。目前只需要知道使用__name__就夠了。
路由和函數(shù)
Web客戶端請求的鏈接地址不同,后臺會通過route來決定每個鏈接對應(yīng)的哪塊處理代碼。最簡單的做法就是使用Flask實(shí)例中提供的方法app.route來注冊一個方法到路由上:
@app.route('/')
def index():
return '<h1>Hello World!<\/h1\>'
Flask路由上是可以配置動態(tài)參數(shù)的:
@app.route('/user/<name>')
def user(name):
return '<h1>Hello, %s!</h1>' % name
在上例中,尖括號中間的內(nèi)容是動態(tài)的,任何匹配了該形式的URL會映射到這個路由上,然后調(diào)用對應(yīng)的View Function。默認(rèn)的,傳遞的參數(shù)被當(dāng)做string處理,當(dāng)然你也可以執(zhí)行它們 比如@app.route /user/<int:id>
。
Server啟動
應(yīng)用程序?qū)嵗幸粋€run方法用于啟動Flask所集成的Web服務(wù)器:
if __name__ == '__main__':
app.run(debug=True)
if判定條件是為了保證:只有該script被直接執(zhí)行的時候才去啟動server,因?yàn)槿绻搒cript是被當(dāng)做模塊引入的,那么很可能在其他的script中已經(jīng)啟動過server了。
啟動過后server會一直輪巡檢查是否收到有客戶端的請求,Mac OS下可以通過ctrl+c 停止server。run方法有很多可選參數(shù)可以配置,比如設(shè)置debug=True
能夠進(jìn)入調(diào)試模式方便查看調(diào)試信息。
一個完整的應(yīng)用
在前面的代碼片段已經(jīng)說明了該例子的各個部分,可以嘗試在自己的編輯器上構(gòu)建這么一個hello.py:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return '<h1>Hello World!</h1>'
if __name__ == '__main__':
app.run(debug=True)
確保保證你是在虛擬環(huán)境下運(yùn)行hello.py,最后訪問 http://127.0.0.1:5000/ 即可看到Hello World頁面。
請求的生命周期
應(yīng)用與請求上下文
每個來自客戶端的請求處理過程都需要構(gòu)建一些對象,比如request對象。
為了將處理請求需要的參數(shù)傳遞給View Function,我們可以給View Function的鏈接中增加動態(tài)參數(shù),但是那樣參數(shù)一多久會顯得混亂了。Flask采用了Context中保存對象的做法,request對象會從context中獲取屬于當(dāng)前請求的參數(shù),以方便全局訪問一些對象,如下就是一個例子:
from flask import request
@app.route('/')
def index():
user_agent = request.headers.get('User-Agent')
return '<p>Your browser is %s</p>' % user_agent
當(dāng)然不同的請求訪問到的是不同的request對象,因?yàn)镕lask中采用了一定的機(jī)制保證獲取對象的正確獲取,邏輯不復(fù)雜有興趣可以細(xì)看相應(yīng)章節(jié)。
在Flask中使用了一個map結(jié)構(gòu)來保存Route和View Function的對應(yīng)關(guān)系,如下示例代碼可以查看該map的存儲鍵值對:
(venv) $ python
>>> from hello import app
>>> app.url_map
Map([<Rule '/' (HEAD, OPTIONS, GET) -> index>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/user/<name>' (HEAD, OPTIONS, GET) -> user>])
鉤子函數(shù)
于面向切面編程概念中,我們通常希望請求前、后可能希望做一些通用的處理,在Flask中可以使用一些鉤子函數(shù)來達(dá)到這個目的,F(xiàn)lask提供了四個鉤子函數(shù):
- before_first_request
- before_request
- after_request
- teardown_request
鉤子函數(shù)的一個典型的應(yīng)用場景是:在第一次請求中通過before_first_request來獲取到用戶數(shù)據(jù)存儲到Context中,以后請求就可以直接從Context中直接取用戶數(shù)據(jù)了。
響應(yīng)結(jié)果
返回給前臺的數(shù)據(jù)可以是一個字符串,還可以攜帶第二個甚至第三個參數(shù):
@app.route('/')
def index():
return '<h1>Bad Request</h1>', 400
更好的做法是返回一個response對象:
from flask import make_response
@app.route('/') def index():
response = make_response('<h1>This document carries a cookie!</h1>')
response.set_cookie('answer', '42')
return response
還有其他一種方式是直接定位到另一個地址:
from flask import redirect
@app.route('/')
def index():
return redirect('http://www.example.com')
有一中特殊的用法,就是abort,用來再頁面處理錯誤直接返回404:
from flask import abort
@app.route('/user/<id>')
def get_user(id):
user = load_user(id) if not user:
abort(404)
return '<h1>Hello, %s</h1>' % user.name
Flask的擴(kuò)展
帶命令行選項(xiàng)的Flask-Script
Flask有大量的用于不同目的的擴(kuò)展可以使用,如果這些還不滿足要求你還可以開發(fā)自己的擴(kuò)展。該部分會介紹如何集成一個用于加強(qiáng)命令行的功能的擴(kuò)展,使命令行能攜帶參數(shù)。
- 第一步,使用pip安裝該擴(kuò)展:
(venv) $ pip install flask-script
- 第二步,基于hello.py修改代碼:
from flask import Flask
rom flask.ext.script import Manager
app = Flask(__name__)
manager = Manager(app)
@app.route('/')
def index():
return '<h1>Hello World!</h1>'
if __name__ == '__main__':
manager.run()
- 第三步,命令行執(zhí)行:
(venv) $ python hello.py
usage: hello.py [-?] {shell,runserver} ...
positional arguments:
{shell,runserver}
shell Runs a Python shell inside Flask application context.
runserver Runs the Flask development server i.e. app.run()
optional arguments:
-?, --help show this help message and exit
如上,必選參數(shù)為runserver/shell, 這里我們要做的是run server。要查看runserver有哪些參數(shù),可以如下方式查看:
(venv) $ python hello.py runserver --help
usage: hello.py runserver [-h] [-t HOST] [-p PORT] [--threaded]
[--processes PROCESSES] [--passthrough-errors] [-d]
[-r]
Runs the Flask development server i.e. app.run()
optional arguments:
-h, --help
-t HOST, --host HOST
-p PORT, --port PORT
--threaded
--processes PROCESSES
--passthrough-errors
-d, --no-debug
-r, --no-reload
現(xiàn)在能夠基于命令行直接設(shè)置server的host和port等參數(shù)了,可以將主機(jī)地址設(shè)置為0.0.0.0看看:
(venv) $ python hello.py runserver --host 0.0.0.0
* Running on http://0.0.0.0:5000/
* Restarting with reloader