Flask自己至關於一個內核,其餘幾乎全部的功能都要用到擴展(郵件擴展Flask-Mail,用戶認證Flask-Login),都須要用第三方的擴展來實現。html
Flask對WSGI (路由)的實現,是採用 Werkzeug,而模板引擎(業務視圖) 則使用 Jinja2。這兩個是Flask框架的核心。前端
Flask核心就是做爲一個Webapp框架的兩個基礎部分:數據庫
除此以外,Flask其它一切的都是由第三方插件實現:
包括:flask
Flask-SQLalchemy:操做數據庫; Flask-migrate:管理遷移數據庫; Flask-Mail:郵件; Flask-WTF:表單; Flask-Bable:提供國際化和本地化支持,翻譯; Flask-script:插入腳本; Flask-Login:認證用戶狀態; Flask-OpenID:認證; Flask-RESTful:開發REST API的工具; Flask-Bootstrap:集成前端Twitter Bootstrap框架; Flask-Moment:本地化日期和時間; Flask-Admin:簡單而可擴展的管理接口的框架
參考Flask擴展列表:http://flask.pocoo.org/extens...瀏覽器
安裝很簡單:安全
$ pip install flask
建議在Virtualenv虛擬環境下安裝,由於Flask須要一系列的依賴,最好給Flask生成一個專用的生產環境,並生產requirement.txt
依賴列表:服務器
# 生產虛擬環境 $ virtualenv ./flask_env # 啓動虛擬環境 $ ./flask_env/bin/active # 生產依賴列表 $ pip freeze > requirements.txt
一個最簡單的Flask程序,只須要三步:cookie
路由規則
,即不一樣路徑能夠實現不一樣的操做。app.run()
,hello-world.py
:網絡
from flask import Flask # 生產一個Flask APP 實例,並指向當前文件(模塊) app = Flask(__name__) # 指定"/"根目錄的路由規則 @app.route('/') def index(): return 'Hello World' # 開始運行app app.run()
Flask中,路由的實現是用裝飾器:@app.route("/")
這種方式來作到的。session
頁面顯示指定內容:
@app.route('/') def index(): return '<h1> 歡迎訪問此頁面 </h1>'
頁面返回指定內容、狀態碼、headers等:
@app.route('/') def index(): body = '<h1> 歡迎訪問此頁面 </h1>' status_code = 200 headers = {'Cache-Control':'no-cache', 'Connection':'keep-alive'} return body, status_code, headers
指定接收的請求方式
:
@app.route('/', method='GET') # ...
給路由傳參數:
@app.route('/orders/<order_id>') def hello_itheima(order_id): return 'The ID of order is: %d' % order_id
限制路由參數的數據類型:
@app.route('/orders/<int:order_id>') # ...
其中int:order_id
是指定參數order_id
必須能轉換成int整數,不然這個請求就會自動被拒絕。
好比用戶請求http://xyz.com/orders/HAHAHAH
,這就不成功。而http://xyz.com/orders/210
這樣的就成功。
中斷請求:
# ... from flask import abort @app.route('/wrong-page') def hello(): # 中斷請求,並返回404狀態碼 abort(404)
處理錯誤請求:
# ... @app.errorhandler(404) def handel_404_error(): return '<h1> The page does not exist </h1>'
其中,若是路由中調用了abort(404)
中斷函數,或是其它產生404錯誤的方法,這個app.errorhandler
都會被自動調用。
返回「渲染」過的模版(即把動態的模版渲染成靜態的HTML):
#... from flask import render_template @app.route('/') def index(): return render_template('index.html')
若是全部路徑的路由都定義在一個文件裏,會很難維護,因此一定要把各個路徑的路由分拆到不一樣的文件裏。
這種分拆很簡單:
正常狀況下,在index.py
主模塊中,咱們仍是同樣正常的定義路由:
#... @app.route('/') def index(): pass
而後咱們能夠把其它路由的處理函數分別放在別的文件裏,好比:register.py
中定義「普通函數」:
def reg(): pass
以及login.py
中定義一個普通函數:
def signin(): pass
而後回到主模塊index.py
中,咱們能夠導入這些函數,並顯式的將這些函數註冊到路由上:
from flask import Flask from register import reg from login import signin app = Flask(__name__) app.route('/register')(reg) app.route('/login')(signin) @app.route('/') def index(): pass
而後咱們能夠用app.url_map
得到當前定義過的全部路由:
print( app.url_map )
咱們手動分割路由處理函數,而後分別導入,這樣雖然也簡單,可是不很差的地方是,主模塊外定義的各個處理函數,自己很難看出來處理的是什麼路由邏輯。
爲此,Flask提供了另外一種路由分割
的方法:即Blueprint
類。
而這個Blueprint類生成的對象,是在子模塊中代替了以前咱們所使用的Flask
類生成的app對象。
也就是說:主模塊仍是用app,可是子模塊中用藍圖blueprint。
假設咱們如今有一個子模塊order.py
定義"/order"
路徑的路由,那麼文件中定義以下:
from flask import Blueprint # 生成藍圖實例:參數中一個是藍圖名稱,一個是主模塊名稱 app_orders = Bluepint('blueprint_orders', __name__) # 將路由添加到藍圖裏 @app_orders.route('/orders') def get_orders(): pass
而後回到主模塊index.py
中,把藍圖註冊到主路由上:
#... from orders import app_orders app = Flask(__name__) app.register_blueprint( app_orders ) #...
Flask提供一個完整請求至迴應的事件流,其中包括:
@app.before_first_request
: 接受第一次請求以前執行@app.before_request
: 接受請求前,每次請求以前都執行。@app.route()
: 處理請求@app.after_request
: 請求以後執行,但前提是請求中沒有出現異常-@app.teardown_request
: 關閉請求時,即每次請求是否異常都會被執行
如下是鉤子的用法:
#... @app.before_first_request def handle_before_first_request(): pass @app.route('/') def index(): pass @app.... def ...
request.current_app
是Flask特有的一種request請求處理
方式,不一樣於flask.request
對象的處理方式,它是能區分多個請求的。
在咱們經常使用的flask.request
對象中,會有一個很嚴重的問題:即它是一個全局變量
。也就是說,若是服務器在處理併發請求時使用的是在同一個進程裏的多線程,那麼不一樣用戶的請求也許會使用同一個flask.request
對象!這時候request中的請求信息就會出現混淆!
因此Flask引入了request.current_app
這個對象,即它可以根據上下文來區分不一樣人的請求。
這是怎麼作到的呢?其實很簡單,它只是把request變爲一個局部變量
而已。這樣一來,每次的request請求,都是各自獨立的局部對象。
除了咱們本身定義返回的信息外,Flask提供了一個內置的make_response
對象,便於處理返回信息。
返回全文信息:
from flask import make_response @app.route('/') def index(): resp = make_response('<h1> 歡迎訪問此頁面 </h1>') resp.status = 200 resp.headers['Cache-Control'] = 'no-cache' return resp
設置cookies:
from flask import make_response @app.route('/') def index(): resp = make_response('<h1> 此頁面會設置你的cookies :) </h1>') resp.set_cookie('uuid', '1230sfjdlsj3uu') resp.set_cookie('name', 'Jason', max_age=360) return resp
其中,max_age
是cookie的存活時間,以s秒爲單位。不設置的話,默認是臨時cookies
,即瀏覽器關閉後立馬失效。
刪除cookie:resp.delete_cookie('uuid')
。注意,這裏的刪除並非立馬刪除瀏覽器中用戶的cookie,而只是把max_age
設置爲0,即瀏覽器關閉後立馬失效。
Flask中有一個request對象,接收了一切對當前模塊的請求數據。
使用的話,直接在@app.route
後面的函數中用def index(request)
接收來自裝飾器的請求對象便可使用。
request參數類型:
經常使用的各類類型操做以下:
from flask import request app = Flask(__name__) @app.route('/', method='POST') def index(request): # Get uploaded file afile = request.files.get('pic') with open('./pic.jpg', 'w') as f: f.write( afile.read() ) # Get a form form = request.from # Dict類型 name = form.get('name') age = form.get('age') # Get cookies uuid = request.cookies.get('uuid') name = request.cookies.get('name')
在登陸頁設置session,並在index頁根據session判斷是否登陸:
from flask import session #... app.config['SECRET_KEY'] = 'asdlkjflaj23jrsdjf任意字符串做爲密鑰kaljdsl;fkja;j' @app.route('/login') def login(): # 設置sessions session['uuid'] = '123abadsf' return '<p> 登陸成功 </p>' @app.route('/') def index(): # 獲取sessions uuid = session['uuid'] # 判別session是否存在 if uuid: return '<p> 以前已登陸過 </p>' else: return '<p> 未登陸,請從新登陸 </p>'
其中,Flask默認狀況下,會利用app.config['SECRET_KEY']
的值做爲一個密鑰,來加密你手動設置的session,而後把這個信息轉換爲名叫session
的cookie存在瀏覽器中。
這個是Flask特別的一點。
可是把敏感的session數據保存到誰都能訪問的cookie中,即便加密了也不是很安全。
因此通常咱們仍是會手動把session數據存到服務器後臺的數據庫中,而不是存到cookie中。
每次驗證再與數據庫進行對比。
動態網頁必需要的就是Form表單。Flask中有自帶的form表單處理方法。不過咱們也能夠用第三方插件Flask-WTF
實現。
這裏咱們先只講自帶的處理方式。
假設咱們有一個表單模版form.html
:
<form method="post"> 用戶名:<input type="text" name="username"> 密碼: <input type="password" name="password"> 確認密碼: <input type="password" name="password2"> <input type="submit" value="提交"><br> {% for message in get_flashed_messages() %} {{ message }} {% endfor %} </form>
當用戶點擊submit提交時,
整個form信息就會用POST方式提交到Flask的路由文件abc.py
中。
咱們進行處理以下:
from flask import Flask from flask import render_template from flask import request app.secret_key = 'abc123' @app.route('/', methods=['GET', 'POST']) def hello(): if request.method == 'POST': # 獲取參數, 並效驗參數完整性, 若是有問題就進行flash username = request.form.get('username') password = request.form.get('password') password2 = request.form.get('password2') if not all([username, password, password2]): flash('params error') elif password != password2: flash('password error') else: print username return 'success' return render_template('Congratulations.html')
通常咱們在開發調試過程當中,能夠用Flask自帶的WSGI和一個小HTTP Server來實現整個App正常運轉。
可是生產環境中,這兩個自帶的組件就效率很低了。因此咱們須要用效率更高的獨立的CGI和獨立的HTTP Server服務器來部署真正的生產環境
通常常見的選項有:
因此,咱們通常採用Nginx + Gunicorn + Flask
來部署網絡應用。
Gunicorn的使用:
# 安裝 $ pip install gunicorn # 進入Flask app的主目錄 cd ./myFlask # 用gunicorn服務器啓動Flask app $ gunicorn -w 4 -b 127.0.0.1:8080 main:app
這個時候,flask就在gunicorn的HTTP服務器上運行了,能夠經過127.0.0.1:8080訪問到app。