Flask-3-视图(可插拔视图)

Posted jiangmingbai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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源码就不贴出来了,想了解可以自己导入后查看,注释写的非常明白,也都有案例


以上是关于Flask-3-视图(可插拔视图)的主要内容,如果未能解决你的问题,请参考以下文章

可插拔自定义视图 Nibs (Nib-in-a-Nib):内存泄漏 - 为啥?

cmdb 可插拔式

Pytorch实现对卷积的可插拔reparameterization

带你手写基于 Spring 的可插拔式 RPC 框架注册中心

利用 Composer 完善自己的 PHP 框架

关于SpringMVC映射模型视图的几点小事