Flask誕生於2010年,是Armin ronacher(人名)用 Python 語言基於 Werkzeug 工具箱編寫的輕量級Web開發框架。
Flask 本身相當於一個核心,其他幾乎所有的功能都要用到擴充套件(郵件擴充套件Flask-Mail,使用者認證Flask-Login,資料庫Flask-SQLAlchemy),都需要用第三方的擴充套件來實現。比如可以用 Flask 擴充套件加入ORM、窗體驗證工具,檔案上傳、身份驗證等。Flask 沒有預設使用的資料庫,你可以選擇 MySQL,也可以用 NoSQL。
其 WSGI 工具箱採用 Werkzeug(路由模組),模板引擎則使用 Jinja2。這兩個也是 Flask 框架的核心。
官網: http://flask.pocoo.org/
官方文件: http://docs.jinkan.org/docs/flask/
Flask常用擴充套件包:
- Flask-SQLalchemy:運算元據庫,ORM;
- Flask-script:終端指令碼工具,腳手架;
- Flask-migrate:管理遷移資料庫;
- Flask-Session:Session儲存方式指定;
- Flask-WTF:表單;
- Flask-Mail:郵件;
- Flask-Bable:提供國際化和本地化支援,翻譯;
- Flask-Login:認證使用者狀態;
- Flask-OpenID:認證, OAuth;
- Flask-RESTful:開發REST API的工具;
- Flask JSON-RPC: 開發rpc遠端服務[過程]呼叫
- Flask-Bootstrap:整合前端Twitter Bootstrap框架
- Flask-Moment:本地化日期和時間
- Flask-Admin:簡單而可擴充套件的管理介面的框架
可以通過 http://flask.pocoo.org/extensions/ 檢視更多flask官方推薦的擴充套件
準備
mkvirtualenv flask_demo -p python3
安裝
pip install flask==0.12.4
建立flask專案
與django不同,flask不會提供任何的自動操作,所以需要手動建立專案目錄,需要手動建立啟動專案的管理檔案
例如,建立專案目錄 flaskdemo,在目錄中建立manage.py.在pycharm中開啟專案並指定上面建立的虛擬環境
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello World'
if __name__ == '__main__':
app.run()
程式碼分析:
# 匯入Flask類
from flask import Flask
"""
import_name Flask程式所在的包(模組),傳 __name__ 就可以
其可以決定 Flask 在訪問靜態檔案時查詢的路徑
static_path 靜態檔案訪問路徑(不推薦使用,使用 static_url_path 代替)
static_url_path 靜態檔案訪問路徑,可以不傳,預設為:/ + static_folder
static_folder 靜態檔案儲存的資料夾,可以不傳,預設為 static
template_folder 模板檔案儲存的資料夾,可以不傳,預設為 templates
"""
app = Flask(__name__)
# 載入專案配置
# 配置類
class Config(object):
DEBUG = True
SECRET_KEY = "abcccddgadsag"
app.config.from_object( Config )
# 指定伺服器IP和埠
app.run(host="0.0.0.0", port=5000, debug = True)
路由的基本定義
# 指定訪問路徑為 demo1
@app.route('/demo1')
def demo1():
return 'demo1'
路由可以設定傳遞引數, 2種方式
# 路由傳遞引數[沒有限定型別]
@app.route('/user/<user_id>')
def user_info(user_id):
return 'hello %s' % user_id
# 路由傳遞引數[限定資料型別]
@app.route('/user/<int:user_id>')
def user_info(user_id):
return 'hello %d' % user_id
路由限定請求方式
from flask import Flask, request
@app.route('/demo2', methods=['GET', 'POST'])
def demo2():
# 直接從請求中取到請求方式並返回
return request.method
正則匹配路由
在 web 開發中,可能會出現限制使用者訪問規則的場景,那麼這個時候就需要用到正則匹配,根據自己的規則去限定請求引數再進行訪問
具體實現步驟為:
- 匯入轉換器基類:在 Flask 中,所有的路由的匹配規則都是使用轉換器物件進行記錄
- 自定義轉換器:自定義類繼承於轉換器基類
- 新增轉換器到預設的轉換器字典中
- 使用自定義轉換器實現自定義匹配規則
程式碼實現
- 匯入轉換器基類
from werkzeug.routing import BaseConverter
- 自定義轉換器
# 自定義正則轉換器
from werkzeug.routing import BaseConverter
class RegexConverter(BaseConverter):
def __init__(self,url_map,*args):
super(RegexConverter, self).__init__(url_map)
# 正則引數
self.regex = args[0]
- 新增轉換器到預設的轉換器字典中,並指定轉換器使用時名字為: re
# 將自定義轉換器新增到轉換器字典中,並指定轉換器使用時名字為: re
app.url_map.converters['re'] = RegexConverter
- 使用轉換器去實現自定義匹配規則
- 當前此處定義的規則是:手機號碼
# 正則匹配路由
@app.route("/login/<re('1\d{10}'):mobile>")
def login(mobile):
return mobile
執行測試:http://127.0.0.1:5000/login/1311111111 ,如果訪問的url不符合規則,會提示找不到頁面
系統自帶轉換器
DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'path': PathConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}
系統自帶的轉換器具體使用方式在每種轉換器的註釋程式碼中有寫,請留意每種轉換器初始化的引數。
from flask import Flask
# 新增一個配置檔案,在配置檔案中設定配置資訊
from config import Config
from flask import request
# from collections import OrderedDict # 有序字典
app = Flask(__name__)
# 呼叫app.config載入配置
app.config.from_object(Config)
from werkzeug.routing import BaseConverter
class RegexConverter(BaseConverter):
def __init__(self,url_map,*args):
super(RegexConverter, self).__init__(url_map)
# 正則引數
self.regex = args[0]
# converter["路由轉換器名稱"] = 實現路由轉換功能的自定義類
app.url_map.converters['re'] = RegexConverter
# 繫結路由
@app.route("/")
def index():
return "hello flask"
# 預設情況下,路由使用的就是關鍵字引數,也叫"命名路由"
# router(路由地址, http請求方式 )
@app.route("/list/<int:page>/<string:content>",methods=["GET","POST"])
def mylist(content,page):
return "第%s頁<br>內容:%s" % (page,content)
# 正則匹配路由
@app.route("/login/<re('1\d{10}'):mobile>")
def login(mobile):
return mobile
http的請求與響應
請求
文件: http://docs.jinkan.org/docs/flask/api.html#flask.request
- request:flask中代表當前請求的
request 物件
- 作用:在檢視函式中取出本次請求資料
- 匯入:
from flask import request
常用的屬性如下:
屬性 | 說明 | 型別 |
---|---|---|
data | 記錄請求的資料,並轉換為字串 | * |
form | 記錄請求中的表單資料 | MultiDict |
args | 記錄請求中的查詢引數 | MultiDict |
cookies | 記錄請求中的cookie資訊 | Dict |
headers | 記錄請求中的請求頭 | EnvironHeaders |
method | 記錄請求使用的HTTP方法 | GET/POST |
url | 記錄請求的URL地址 | string |
files | 記錄請求上傳的檔案 | * |
json | 記錄請求的json資料 | json |
獲取請求中查詢字串
http://127.0.0.1:5000/demo1?a=10
......
"""獲取客戶端的請求"""
@app.route("/request")
def req1():
"""獲取查詢字串"""
query_string = request.args
print(query_string)
# 瀏覽器輸入 http://127.0.0.1:5000/request?a=1&b=2
"""列印效果: ImmutableMultiDict([('a', '1'), ('b', '2')])"""
# 獲取一個引數的一個值
http://127.0.0.1:5000/request?username=abcd
username = request.args.get("username")
# print(username)
"""列印效果: abcd """
# 獲取一個引數的多個值
# http://127.0.0.1:5000/request?username=xiaoming&love=吹牛&love=睡覺
love = request.args.getlist("love")
# print(love)
"""列印效果: ['吹牛', '睡覺']"""
# 把傳遞過來的資料抓換成原生的字典
data = request.args.to_dict()
# print(data)
"""列印效果:{'username': 'xiaoming', 'love': '吹牛'} """
return "ok"
@app.route("/request2",methods=["POST"])
def req2():
"""獲取post資料和請求頭"""
# 必須傳 json 格式的資料
# print( request.data )
# """列印結果:
# b'{\n\t"username":"xiaoming",\n\t"age":18,\n\t"sex":1\n}'
# """
# 方式一
# import json
# from flask import json
# data = json.loads(request.data)
# print(data)
# """列印結果:
# {'username': 'xiaoming', 'age': 18, 'sex': 1}
#方式二
print(request.json)
# """列印結果:
# {'username': 'xiaoming', 'age': 18, 'sex': 1}
# """
#
# """獲取請求行資料"""
# print( request.headers )
# print( request.headers.to_list() )
"""獲取上傳檔案"""
print( request.files )
print( request.files.get("avatar") )
"""列印效果:
ImmutableMultiDict([('avatar', <FileStorage: 'avatar.png' ('image/png')>)])
<FileStorage: 'avatar.png' ('image/png')>
"""
return "ok"
if __name__ == '__main__':
app.run()
響應
flask預設支援2種響應方式:
- 資料響應:
預設響應html文字,也可以返回 JSON格式 - 頁面響應:
重定向 url_for
響應的時候,flask也支援自定義http響應狀態碼
響應html文字
@app.route("/")
def index():
# [預設支援]響應html文字
return "<img src='http://flask.pocoo.org/static/logo.png'>"
返回JSON資料
在 Flask 中可以直接使用 jsonify 生成一個 JSON 的響應
from flask import Flask, request, jsonify
@app.route("/")
def index():
# 也可以響應json格式程式碼
data = [
{"id":1,"username":"liulaoshi","age":18},
{"id":2,"username":"liulaoshi","age":17},
{"id":3,"username":"liulaoshi","age":16},
{"id":4,"username":"liulaoshi","age":15},
]
return jsonify(data)
flask中返回json 資料,都是flask的jsonify方法返回就可以了.
重定向
重定向到百度頁面
# 頁面跳轉響應
from flask import Flask, request, jsonify, redirect
@app.route("/user")
def user():
# 頁面跳轉 redirect函式就是response物件的頁面跳轉的封裝
# Location: http://www.baidu.com
return redirect("http://www.baidu.com")
重定向到自己寫的檢視函式
可以直接填寫自己 url 路徑
也可以使用 url_for 生成指定檢視函式所對應的 url
# 內容響應
@app.route("/")
def index():
# [預設支援]響應html文字
# return "<img src='http://flask.pocoo.org/static/logo.png'>"
# 也可以響應json格式程式碼
data = [
{"id":1,"username":"liulaoshi","age":18},
{"id":2,"username":"liulaoshi","age":17},
{"id":3,"username":"liulaoshi","age":16},
{"id":4,"username":"liulaoshi","age":15},
]
return jsonify(data)
#使用url_for可以實現檢視方法之間的內部跳轉
# url_for("檢視方法名")
from flask import Flask, request, jsonify, redirect, url_for
@app.route("/login")
def login():
return redirect( url_for("index") )
重定向到帶有引數的檢視函式
在 url_for 函式中傳入引數
# 路由傳遞引數
@app.route('/user/<user_id>')
def user_info(user_id):
return 'hello %s' % user_id
# 重定向
@app.route('/demo4')
def demo4():
# 使用 url_for 生成指定檢視函式所對應的 url
return redirect(url_for('user_info', user_id=100))
自定義狀態碼
在 Flask 中,可以很方便的返回自定義狀態碼,以實現不符合 http 協議的狀態碼,例如:status code: 666
@app.route('/demo4')
def demo4():
return '狀態碼為 666', 400
會話控制
所謂的會話,就是使用者和瀏覽器中網站之間一次互動過程.
會話的開始是在使用者開啟瀏覽器以後第一次訪問網站.
會話的結束時在使用者關閉瀏覽器以後.
因為 http 是一種無狀態協議,瀏覽器請求伺服器是無狀態的。
無狀態:指一次使用者請求時,瀏覽器、伺服器無法知道之前這個使用者做過什麼,每次請求都是一次新的請求。
無狀態原因:瀏覽器與伺服器是使用 socket 套接字進行通訊的,伺服器將請求結果返回給瀏覽器之後,會關閉當前的 socket 連線,而且伺服器也會在處理頁面完畢之後銷燬頁面物件。
有時需要保持下來使用者瀏覽的狀態,比如使用者是否登入過,瀏覽過哪些商品等
實現狀態保持主要有兩種方式:
- 在客戶端儲存資訊使用
Cookie,本地儲存,token[jwt,oauth]
- 在伺服器端儲存資訊使用
Session
,redis
Cookie
Cookie是由伺服器端生成,傳送給客戶端瀏覽器,瀏覽器會將Cookie的key/value儲存,下次請求同一網站時就傳送該Cookie給伺服器(前提是瀏覽器設定為啟用cookie)。Cookie的key/value可以由伺服器端自己定義。
使用場景: 登入狀態, 瀏覽歷史, 網站足跡
Cookie是儲存在瀏覽器中的一段純文字資訊,建議不要儲存敏感資訊如密碼,因為電腦上的瀏覽器可能被其它人使用
Cookie基於域名安全,不同域名的Cookie是不能互相訪問的
如訪問luffy.com時向瀏覽器中寫了Cookie資訊,使用同一瀏覽器訪問baidu.com時,無法訪問到luffy.com寫的Cookie資訊
瀏覽器的同源策略針對cookie也有限制作用.
當瀏覽器請求某網站時,會將本網站下所有Cookie資訊提交給伺服器,所以在request中可以讀取Cookie資訊
設定cookie
設定cookie需要通過flask的Response響應物件來進行設定,由flask內部提供了一個make_response函式給我們可以快速建立響應物件
from flask imoprt Flask,make_response
@app.route('/set_cookie')
def set_cookie():
resp = make_response('this is to set cookie')
resp.set_cookie('username', 'xiaoming', max_age=3600)
# max_age 為cookie有效期,單位為秒
return resp
獲取cookie
from flask import Flask,request
@app.route('/get_cookie')
def resp_cookie():
resp = request.cookies.get('username')
return resp
Session
對於敏感、重要的資訊,建議要儲存在伺服器端,不能儲存在瀏覽器中,如使用者名稱、餘額、等級、驗證碼等資訊
在伺服器端進行狀態保持的方案就是Session
注意: Session依賴於Cookie,而且flask中使用session,需要配置SECRET_KEY選項,否則報錯.
設定session
from flask import session
@app.route('/set_session')
def set_session():
session['username'] = 'xiaoming'
return 'ok!'
獲取session
@app.route('/get_session')
def get_session():
return session.get('username')