Flask-3-视图(可插拔视图)
前沿:本次分享主要是基于类的视图
一、什么是视图函数?
简单来说,被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源码就不贴出来了,想了解可以自己导入后查看,注释写的非常明白,也都有案例