前沿:本次分享主要是基於類的視圖
一、什么是視圖函數?
簡單來說,被url裝飾的==>后面處理邏輯的方法就是視圖函數,一般制作三件事,接收請求參數,數據處理邏輯、構建響應對象對並返回
一般來說視圖函數內的邏輯不應該過長,具體邏輯在另外的模塊去封裝,等封裝的盡量盡快封裝,不要等以后,以后重構的話更麻煩更累。
二、視圖函數的形式
1、分請求方法
路由中可以根據不同的請求方法來返回不同的東西
比如: project 如果是get請求就返回project信息
如果是post請求 就新增一個project
2、分請求單復數
路由中可以根據參數來動態決定響應對象,例如 project 接口 如果傳了id,就返回對象id,的項目信息,如果沒有穿則返回全部項目信息,可以定義一個默認id值,defaults = {"id":None}
3、注意視圖函數對應MVC的部分,不要越界
視圖函數應該負責哪一塊已經反復強調幾次,不在重復
4、注意:
上述說的視圖形式,只是一種舉例,具體怎么使用,完全靠自己習慣,你要寫兩個視圖函數來實現,一個視圖函數只做一件事情。這種也是完全OK的。遵循RESTFUL那一套也是很好,不過對於前端后不分離,我還是喜歡寫一個視圖中,這樣處理會省事些。
三、基於類的視圖(也可以叫可插拔視圖)
1、什么是基於類的視圖?
falsk從Django那學來,以類的方式實現視圖函數的邏輯,封裝get,post函數,如果請求方法是get就掉用類中get函數,如果是post請求,就掉類中post的函數,根據請求方法來和類中的函數弄一個綁定關系,達到這種映射的效果,不過需要繼承flask的View類。
2、類視圖有什么好處
- 類是可以繼承的
- 代碼可以復用
- 可以定義多中行為
- 上述說了一個視圖實現多個功能的,邏輯就很多 ,此時我們用基於類的視圖則比較優雅
3、可插拔視圖案例
- 需要繼承View
- 必須重寫dispatch_request方法,主要實現請求調度的作用。
- 請求方法的限制,可以放在類的methods屬性定義
- 裝飾器也可以使用自定義裝飾器,用decorators屬性定義
- 類視圖寫完我,不能用flask的app.route裝飾器來注冊路由,只能用add_url_rule方法,綁定視圖時用as_view()意思是將類轉成視圖函數用,接收一個name參數,定義視圖函數的名字,或者說定義端點名。因為端點默認取的就是視圖函數的名字
- View類中都有說明,可參考VIew源碼
from flask.views import View
from flask import Flask, request
# 基於類的視圖
class Project(View):
# 定義請求方法
methods = ["GET", "POST"]
# get請求方法的執行邏輯
def get(self):
return "get"
# post請求方法執行的邏輯
def post(self):
return "post"
# 調度函數,必須重寫。不重寫,View類會直接拋異常
def dispatch_request(self):
# 請求方法映射關系
request_method = {"get": self.get, "post": self.post}
# 通過requset方法獲取前端訪問的請求方法
print(request.method)
# 通過請求方法,映射到對應的函數對象
view = request_method.get(request.method.lower())
print(view)
# 返回映射到的函數返回值
return view()
app = Flask(__name__)
# 只能采用集中注冊,用as_view方法
app.add_url_rule("/project", view_func=Project.as_view("project"))
# 可以打印看一下視圖和url的綁定關系
print(app.url_map)
if __name__ == '__main__':
app.run(debug=True)
四、來自Flask的優化MethodView類。
上述我們自己些調度函數dispatch_request,屬於硬編碼,這種映射關系是我們寫死的。非常不優雅。而falsk給我們另外基於View類封裝一個MethodView,它里面幫我用獲取類屬性的方式,也就是用getattr的方法,更加優化的重寫了View類的dispatch_request方法
說這么多,所以呢?有什么用?
只要我們的類視圖繼承這個MethodView類,我們就不需要在每個類視圖中在重寫dispatch_request。完全不需要在寫這個方法了,除非你還有別的要擴展可以超繼承或者重寫都行
from flask.views import View, MethodView
from flask import Flask, request
class Project(MethodView):
methods = ["GET", "POST"]
def get(self,project_id=None):
if project_id is None
return "所有項目"
return "單個項目"
def post(self):
return "post"
# 注釋掉也是一樣的效果,不需要在寫了
# def dispatch_request(self):
# request_method = {"get": self.get, "post": self.post}
# print(request.method)
# view = request_method.get(request.method.lower())
# print(view)
# return view()
app = Flask(__name__)
app.add_url_rule("/project/<project>", view_func=Project.as_view("project"),methods=["GET"])
print(app.url_map)
if __name__ == '__main__':
app.run(debug=True)
五、類視圖實現不同功能是的注冊機制
類視圖非常適合對同一個范疇的東西,不同的功能實現,如項目操作,查詢單個項目、查詢所有項目、創建項目、刪除項目、更新項目等等,此時我們一個類視圖就都能實現了,但是在注冊的時候 需要分開注冊成不同的路由。
from flask.views import View, MethodView
from flask import Flask, request
class Project(MethodView):
def get(self, project_id=None):
if project_id is None:
return "所有項目"
return "單個項目"
def post(self):
return "創建項目"
def delete(self,project_id):
return "刪除項目"
app = Flask(__name__)
view_func = Project.as_view("project")
# 類視圖實現多個功能,我們要集中也建立多個路由,對處理
# 獲取單個項目,或刪除
app.add_url_rule("/project/<int:project_id>", view_func=view_func, methods=["GET","DELETE"])
# 獲取所有項目
app.add_url_rule("/projects", view_func=view_func, methods=["GET"])
# 創建項目
app.add_url_rule("/project/create", view_func=view_func, methods=["POST"])
print(app.url_map)
if __name__ == '__main__':
app.run(debug=True)
基於MethedVeiew,采用TESTFUL的設計思路
URL | 方法 | 功能說明 |
---|---|---|
/projects/ | GET | 獲取項目列表 |
/projects/ | POST | 創建一個項目 |
/projects/
|
GET | 獲取一個項目 |
/projects/
|
PUT | 更新一個項目 |
/projects/
|
delete | 刪除一個項目 |
.... | ..... | .... |
傳統的視圖函數(前端后不分離的情況)
我們通常會在函數加很多if判斷
@app.route("/projects/<project_id>", methods=["GET", "POST", "PUT", "DELETE"])
def project(project_id):
method = request.method
if method == "GET":
return f"get {project_id}"
elif method == "post":
return f"post {project_id}"
# .....
return "其他的方法判斷"
六、總結:
- 基於類的視圖,能夠比較優雅的方式實現很多復雜的不同功能
- 類視圖定義請求方法,需要加類屬性:methods = ['GET']
- 要明白類視圖其中是怎么通過請求方法,調度的,核心是基於dispatch_request方法調度的
- 不能用@app.route()注冊
- 只能用app.add_url_rule("url",類對象.as_view(視圖名字/端點名))
- as_view 最后就是調用dispatch_request方法。
- 類視圖用裝飾器時,不能在類和類方法上直接裝飾,因為我們要裝飾的是視圖函數(也就是最后執行的是調度類函數),View類中幫我們定義了一個增加裝飾器的方法,定義類屬性 decorators = [裝飾器函數名]
- 說明:view和methodView源碼就不貼出來了,想了解可以自己導入后查看,注釋寫的非常明白,也都有案例