一共郭、Flask 簡介
Flask是一個使用 Python 編寫的輕量級 Web 應(yīng)用框架。其 WSGI 工具箱采用 Werkzeug 烦秩,模板引擎則使用 Jinja2 澈缺。Flask使用 BSD 授權(quán)。
Flask也被稱為 “microframework” 塌鸯,因為它使用簡單的核心侍瑟,并且被設(shè)計為可擴展形式。故而沒有提供一些重要的功能丙猬,例如數(shù)據(jù)庫和用戶認(rèn)證涨颜,所以開發(fā)者可以自由選擇最適合程序的包,或者按照需求自行開發(fā)茧球。
社區(qū)成員開發(fā)了大量的不同用途的擴展庭瑰,如果這還不能滿足需求,你還可以使用所有Python標(biāo)準(zhǔn)包或代碼庫抢埋。
二弹灭、Flask 安裝
一般安裝python后會自帶pip工具,方便下載安裝python各類庫揪垄,如果沒有自行百度鲤屡。
pip install flask
三、最簡單Flask應(yīng)用
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return "Hello World!"
if __name__ == '__main__':
app.run() # 啟動服務(wù)器
寫完后直接用python運行福侈,默認(rèn)監(jiān)聽本地5000端口,訪問http://127.0.0.1:5000/就能看到Hello World!
四卢未、初始化應(yīng)用
所有Flask程序都必須創(chuàng)建一個程序?qū)嵗?/code>肪凛,所有功能都是圍繞這個實例進行的堰汉,接收自客戶端的所有請求都將轉(zhuǎn)交到這個對象處理。程序?qū)嵗荈lask類的對象伟墙,經(jīng)常使用下述代碼創(chuàng)建一個實例:
from flask import Flask
app = Flask(__name__)
五翘鸭、路由和視圖函數(shù)
-
路由
客戶端(如Web瀏覽器)把請求發(fā)送給Web服務(wù)器,Web服務(wù)器再把請求發(fā)送給Flask程序?qū)嵗量绦驅(qū)嵗枰缹γ總€URL請求運行哪些代碼就乓,所以保存了一個URL到Python函數(shù)的映射關(guān)系。處理URL和函數(shù)之間關(guān)系的程序稱為路由
拱烁。
-
視圖函數(shù)
前面最簡單的Flask應(yīng)用中定義了一個函數(shù)hello_world()
生蚁,該函數(shù)被注冊為程序根地址(/)的處理程序,也就是訪問http://127.0.0.1:5000/時戏自,會觸發(fā)服務(wù)器執(zhí)行hello_world()
函數(shù)邦投,函數(shù)的返回值成為響應(yīng)
,是客戶端接收到的內(nèi)容擅笔,如果客戶端是Web瀏覽器志衣,響應(yīng)就是返回給用戶的HTML文檔。
像hello_world()
這樣的用于處理請求的函數(shù)稱為視圖函數(shù)
猛们。視圖函數(shù)可以返回簡單的HTML字符串念脯,也可以返回一個完整的HTML文檔(這里就要用到Jinja2模板引擎啦)。
- 注冊一個視圖函數(shù)最常用的方法就是用
app.route()
:
@app.route("/")
def hello_world():
pass
- 限制路由的請求方法
@app.route("/", methods=["GET"])
def hello_world():
pass
這樣弯淘,要是客戶端以POST的方式請求該路由绿店,就會返回“405 Method Not Allowed”
- 向路由函數(shù)傳參
有的時候我們需要通過url獲取有用的信息,比如說知道來訪者的姓名耳胎,以便在返回的歡迎語中加入他的名字惯吕。
@app.route("/hello/<string:name>")
def hello(name):
return "hello, " + name
上例中,在定義該路由的訪問路徑里加了一個<string:name>怕午,并增加了一個同名函數(shù)參數(shù)废登。
更一般的情況是<type:param>,其中type是類型郁惜,常用的有string堡距、int,param就是參數(shù)名兆蕉,它會傳遞到路由函數(shù)的同名參數(shù)里羽戒。
六、啟動服務(wù)器
當(dāng)Flask應(yīng)用被初始化且視圖函數(shù)定義好之后虎韵,就可以啟動Flask應(yīng)用啦易稠。
if __name__ == "__main__":
app.run() # 默認(rèn)監(jiān)聽本地5000端口
# app.run(port=8080) 監(jiān)聽8080端口
七、請求 - 響應(yīng)循環(huán)
說到請求包蓝,必須要先介紹一下上下文
-
上下文(Context)
上下文驶社,在閱讀文章時經(jīng)常提到企量,意思是語境、語意亡电。在程序設(shè)計中届巩,上下文的概念也是類似的,你可以這么理解:
通俗地講份乒,每一段代碼都有許多外部變量恕汇,比如一個函數(shù)需要傳入若干個必填的參數(shù)才能夠運行,那些參數(shù)就是上下文的一部分或辖,意味著該函數(shù)無法獨立運行瘾英,需要上下文
的支持。而許多函數(shù)都是需要各種參數(shù)才能運行的孝凌,這些參數(shù)組成的集合就稱為上下文方咆。
-
Flask中的上下文
變量名 | 上下文 | 說明 |
---|---|---|
current_app | 程序上下文 | 當(dāng)前激活程序的程序?qū)嵗?/td> |
g | 程序上下文 | 上下文全局變量 |
request | 請求上下文 | 請求對象,封裝了客戶端發(fā)出的HTTP請求中的內(nèi)容 |
session | 請求上下文 | 用戶會話蟀架,用戶儲存同一個客戶端在多個請求間需要“記住”的信息 |
-
請求上下文
請求上下文變量是在視圖函數(shù)被觸發(fā)時傳入的一個HTTP請求對象瓣赂,儲存了所有客戶端發(fā)送過來的數(shù)據(jù),因此該變量只有在視圖函數(shù)中才能訪問片拍。如果難以理解煌集,你只需要記住request變量只有在視圖函數(shù)中才能訪問
我們可以通過以下方式引入請求上下文變量:
from flask import request
-
請求上下文變量常用的訪問操作有:
request.args 獲取所有GET請求參數(shù)
request.form 獲取所有form-data、x-www-form-urlencoded類型的請求參數(shù)
request.json 獲取所有json類型的請求參數(shù)
request.method 獲取請求方法
request.headers 獲取請求頭 -
請求鉤子
什么是鉤子(Hook)捌省?
打個比方苫纤,魚鉤是用來釣魚的,一旦魚咬了鉤纲缓,鉤子就一直鉤住魚了卷拘,任憑魚在水里怎么游,也逃不出魚鉤的控制祝高。在程序設(shè)計里栗弟,鉤子就是一個事件,鉤住了某段代碼工闺,任憑這段代碼這么運行乍赫,都逃不過我的鉤子事件。-
Flask里的請求鉤子
鉤子 說明 before_first_request 注冊一個函數(shù)陆蟆,在處理第一個請求之前運行 before_request 注冊一個函數(shù)雷厂,在每次請求之前運行 after_request 注冊一個函數(shù),如果沒有未處理的異常拋出叠殷,在每次請求之后運行 teardown_request 注冊一個函數(shù)改鲫,即使有未處理的異常拋出,也在每次請求之后運行 用法
from flask import request @app.before_request def app_before_request(): print("HTTP {} {}".format(request.method, request.url))
這樣在每次請求時都會輸出請求方式和請求url,但其實鉤子函數(shù)的作用遠不止這些钩杰。
-
響應(yīng)
通常纫塌,每個視圖函數(shù)都有返回值,而最簡單的就是一串字符串了讲弄,F(xiàn)lask默認(rèn)返回的類型是text/html,狀態(tài)碼為200依痊。狀態(tài)碼很重要避除,如果需要修改,我們可以這樣做:
@app.route("/") def hello_word(): return "Not Found", 404
當(dāng)然胸嘁,如果要自定義響應(yīng)瓶摆,最好還是引入make_response函數(shù),該函數(shù)接受一個bytes對象(二進制數(shù)據(jù))或者字符串作為響應(yīng)主體性宏,并返回一個響應(yīng)對象response群井,通過這個對象我們可以自定義該響應(yīng)的頭部,比如修改響應(yīng)頭部的Content-Type和Content-Disposition來告訴客戶端這個文件是需要被下載的毫胜,并且將From設(shè)置為Ncuhome來告訴客戶端該文件來自家園工作室书斜。
@app.route("/download") def download(): response = make_response(open("lesson.md", "rb").read()) response.headers["From"] = "Ncuhome" response.headers["Content-Type"] = "application/octet-stream; charset=utf-8;" response.headers["Content-Disposition"] = "attachment;filename=lesson.md" return response
-
快速構(gòu)建一個json格式的響應(yīng)
前后端交互時,一般都是使用JSON格式數(shù)據(jù)進行交互
from flask import jsonify @app.route('/hello', methods=['GET']) def user(user_id): if not user_id == 1: abort(404) return jsonify({ "status": 1, "data": { "username": "ncuhome", "desc": "Hello, Ncuhomer!", }, "message": "獲取成功" })
-
其他一些響應(yīng)
- 重定向
from flask import redirect @app.route("/ncuos") def ncuos(): return redirect("https://www.ncuos.com/")
- 重定向到某個路由
from flask import url_for @app.route("/redirect_to_hello") def redirect(): return redirect(url_for("hello")) @app.route("/hello") def hello(): return "Hello, Ncuhomer!"
- 返回HTTP狀態(tài)碼
from flask import abort @app.route("/user/<int:user_id>") def get_user(user_id): abort(404)
Jinja2 模板引擎
前面提到了Jinja2酵使,它的作用其實是為了方便構(gòu)造HTML文檔荐吉、以及其他的一些文檔內(nèi)容(郵件等)。
- 響應(yīng)返回完整HTML
簡單舉個栗子吧
模板文件 ./template/index.html
其中name就是我們需要填補的口渔,它用花括號{{ }}括起來了样屠。<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Ncuhome Demo</title> </head> <body> Hello, {{ name }} </body> </html>
填補name并返回完整HTML:from flask import render_template @app.route("/hello/<string:name>") def hello(name): return render_template("index.html", name=name)
- 模板中的for循環(huán)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Ncuhome Demo</title> </head> <body> {% for user in users %} {{ loop.index }}: {{ user }} <br> {% endfor %} </body> </html>
from flask import render_template @app.route("/users") def hello(name): users = ["Amy", "David", "Sam"] return render_template("index.html", users=users)
- 模板中的if
if和for類似,都擁有一個作用域缺脉,用法也一樣痪欲。{% if name %} {{ name }} {% endif %}