1.初始化
所有的flask程序都必須創建一個程序實例
web服務器使用wsgi接口協議,把接收客戶端的請求都轉發給這個程序實例來進行處理。這個程序實例就是flask對象
from flask import Flask app = Flask(__name__)
#__name__決定程序的根目錄,以便以后能找到相對於程序根目錄的資源文件位置
2.路由和視圖函數
程序實例需要知道接收請求后,需要知道url請求應該運行哪些代碼。所以保存了一個url和python函數的映射關系;這個映射關系就叫做路由
flask程序中路由的寫法:
2.1#使用app.route裝飾器,把修飾的函數注冊為路由。例如
@app.route('/') def index(): return "<h1>Hello World</h1>"
#函數的名字不是必須寫index的,只是和裝飾器關聯的時候寫的函數名而已
#把index函數注冊為程序根路徑的處理程序。函數的返回值稱為響應,是客戶端接收的內容。
像index這樣的函數稱為試圖函數,試圖函數返回的響應可以是包含html的簡單字符串,也可以是復雜的東西
2.2#可變url部分映射,使用特定的裝飾器語法就可以
@app.route('/user/<name>') def user(name): return "<h1>hello %s</h1>"%(name)
裝飾器中的<name>指定可變內容為name,name對user(name)函數中的傳遞參數,這2個部分內容必須一致
調用試圖函數時候,flask會自動的將動態部分作為參數傳入參數,這個函數中,參數用於生成個人的歡迎信息
#備注:路由中的動態部分默認使用字符串類型,可以使用int,float,path來定義;例如<int:id>;path類型也是字符串,但不把斜線視作分隔符,而將其當做動態片段的一部分
3.啟動服務器
調用程序實例app的run方法啟動flask集成開發的web服務器
if __name__ == "__main__": app.run(debug=True)
debug=True代表的是調試模式,這個flask自帶的run方法開啟的服務器不適合在生產中使用,此處只用來測試
4.一個完整的Flask程序
啥也不說,先上例子hello.py
from flask import Flask app = Flask(__name__) @app.route('/') def index(): return '<h1>HelloWorld</h1>' @app.route('/user/<name>') def user(name): return "<h1>hello %s</h1>"%name if __name__ == "__main__": app.run(debug=True)
默認會開啟服務器本機5000端口;127.0.0.1:5000
執行腳本python hello.py
瀏覽器測試http://127.0.0.1:5000/
http://127.0.0.1:5000/user/xiaobai
5.請求上下文
Flask使用請求上下文,臨時把某些對象變為全局可用;例如
from flask import request @app.route('/') def index(): user_agent = request.headers.get('User-Agent') return '<h1>your browser is %s</h1>'%(user_agent)
在這個視圖函數中,我們把request當做全局變量使用,flask使用請求上下文讓特定的變量在一個線程中全局可訪問。於此同時卻不會干擾其他線程
session:請求上下文;用戶會話,用於存儲請求之間需要“記住”的值的詞典
激活請求上下文的后就可以使用request和session變量了
6.程序上下文
current_app:程序上下文;當前激活程序的程序實例
g:程序上下文;處理請求時用作臨時存儲的對象
7.請求映射關系表
接收請求,處理請求,,,之間有個映射表,要不然不知道該去執行什么代碼。URL映射
from hello import app print app.url_map
Map([<Rule '/' (HEAD, OPTIONS, GET) -> index>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/user/<name>' (HEAD, OPTIONS, GET) -> user>])
8.請求鈎子
有的時候在處理請求之前和之后,執行某些特定的代碼是很有用的,這就用到了請求鈎子
例如在請求之前創建數據庫連接或者redis連接;或者是系統里面用戶請求處理之前先驗證用戶的身份,是否激活,激活執行什么操作,沒激活用戶一直綁到固定頁面去直到激活
為了避免每個試圖函數中都使用重復的代碼,flask提供了注冊通用函數的功能;
也就是說只要寫一個請求鈎子-函數,整個程序實例全局都被應用了。
例如:在所有請求之前先驗證下用戶的認證狀態
@before_app_request def before_request(): if current_user.is_authenticated: current_user.ping() if not current_user.confirmed and request.endpoint[:5] != 'auth.' and request.endpoint != 'static': return redirect(url_for('auth.unconfirmed'))
常見的4種鈎子:
before_first_request:注冊一個函數,在處理第一個請求之前運行
before_request:注冊一個函數,每次請求之前運行
after_request:注冊一個函數,沒有未處理的異常拋出,每次請求之后運行
teardown_request:注冊一個函數,有未處理的異常拋出,每次請求之后運行
在請求鈎子和視圖函數之間共享數據一般使用程序上下文g;
例如before_request處理程序可以從數據庫中加載已登錄用戶,將其保存到g.user中,隨后調用試圖函數,試圖函數再從g.user中獲取用戶
9.基於Flask的http響應
flask調用試圖函數處理請求,並把返回值作為響應的內容.大多情況下是一個簡單的字符串或者json字符串;返回字符串常用於給對方提供接口的時候使用
http響應中很重要的一個內容是狀態碼,flask默認設置為200,這個代碼表明請求已經被成功處理了
如果試圖函數返回的響應需要不同的狀態碼,可以把狀態碼加到后面返回
例如
@app.route('/') def index(): return '<h1>Bad Request</h1>',400
試圖函數返回的響應還可以接受第三個參數,第三個參數是一個字典類型的首部,可以添加到http響應中去,一般不用添加
如果不想返回這種好多個元素的元祖,可以使用Response對象來標准化下返回。
例如:創建一個響應對象,然后設置cookie
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
還有一種特殊的響應類型,flask提供了一種基於302的跳轉響應,這個響應由redirect函數來提供。指向的地址由Location首部提供,重定向的響應可以使用3個值形式的返回值生成。也可以再Response對象中設定
例如:
from flask import redirect @app.route('/') def index(): return redirect('http://www.example.com')
還有一種特殊的響應類型,flask提供了一種錯誤響應。這個由abort函數來提供。abort拋出404異常,拋出異常后把控制權移交給web服務器
例如:
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)
10.flask的擴展flask-script
這個例子主要是講如何把flask擴展添加到程序中,並使用
例如下面你的例子是添加flask-script擴展,使用命令行參數增強程序的功能
使用命令行方式啟動web服務器,而不是修改文件,給run方法傳遞參數
安裝擴展
pip install flask-script
使用flask-script擴展,並把hello.py文件改為命令行參數啟動的形式#添加的擴展默認會安裝到flask.ext命名空間中
from flask import Flask from flask.ext.script import Manager app = Flask(__name__) manager = Manager(app) @app.route('/') def index(): return '<h1>HelloWorld</h1>' @app.route('/user/<name>') def user(name): return "<h1>hello %s</h1>"%name if __name__ == "__main__": manager.run()
flask-script擴展中添加了一個Manager的類,以上例子中,這個擴展初始化的方法是,把程序實例作為參數傳遞給構造函數來初始化主類的實例。后續其他flask擴展也基本是這個套路
這樣修改之后,程序就可以使用一組基本的命令行選項來啟動和調試了
python hello.py shell#在flask應用上下文環境中運行python shell,方便測試和調試web環境
python hello.py runserver#運行flask開發服務器,app.run()
python hello.py -h#顯示幫助信息
python hello.py runserver --help
usage: hello.py runserver [-h] [-t HOST] [-p PORT] [--threaded]
[--processes PROCESSES] [--passthrough-errors] [-d]
[-r]
python hello.py runserver -h 0.0.0.0 -p 80#這樣就開啟了本機的80端口,別的機器可以遠程訪問了