Flask快速入门(4) — CBV写法与解析

目录

方式一:继承View

from flask import Flask, views
app = Flask(__name__)

class IndexView(views.View):
    methods = ['GET']

    def dispatch_request(self):
        print('index')
        return 'Index!'

app.add_url_rule('/index', view_func=IndexView.as_view(name='name'))
if __name__ == '__main__':
    app.run()

同django一样,flask中cbv模式时也是需要

1:自定义一个视图函数类,继承flask.view.View

2:执行as_view()方法,只不过在这里as_view必须要有一个参数name。这里为什么要有name呢?

3:在视图函数类中定义dispatch_request方法,为什么必须要写呢该方法呢.

来看下源码怎么执行,顺便解答一下疑惑。首先是视图类执行as_view方法。先从自定义的类查找,没有再查找父类,即View.as_view()

as_view()源码分析

@classmethod  # 是一个类方法,此时cls表示自定义的类IndexView
def as_view(cls, name, *class_args, **class_kwargs):  # 第一个位置参数没有默认值,所以必须要传
    def view(*args, **kwargs):   # 请求来了执行
        self = view.view_class(*class_args, **class_kwargs)  # cls()实例化一个对象
        return self.dispatch_request(*args, **kwargs)  # 执行dispath_request()方法,如果在自定义类中没有定义该方法,则执行父类的dispatch_request(),点进去其实就是raise NotImplementedError()
    
    if cls.decorators:
        view.__name__ = name
        view.__module__ = cls.__module__
        for decorator in cls.decorators:
            """在这里对decorators循环遍历,然后再将view函数传入执行。其实就是装饰器"""
            view = decorator(view)

    view.view_class = cls
    view.__name__ = name  # 给view函数重命名,这样在该方法 return view时返回的是不同的函数名,遵循路由与视图函数一一对应的元则
    view.__doc__ = cls.__doc__
    view.__module__ = cls.__module__
    view.methods = cls.methods
    view.provide_automatic_options = cls.provide_automatic_options
    return view  # 返回的是一个函数名,这样当请求来的时候执行的就是view()函数 

总结:

(1)自定义视图类继承flask.views.View时,必须要重写dispatch_request()方法。在该方法中来分发请求方式执行相应的功能

(2)在as_view()中必须要传一个name参数。就是相当于endpoint起了一个别名用于反向解析路由。有endpoint反向解析用endpoint,没有就用name的值

(3)不同的路由不能起相同的别名。应遵循路由与视图函数一一对应的元则,比如这样是不行的

app.add_url_rule('/index', view_func=IndexView.as_view(name='name'))
app.add_url_rule('/login', view_func=IndexView.as_view(name='name'))

方式二:继承MethodView

from flask import Flask,views

app = Flask(__name__)
class IndexView(views.MethodView):
    methods = ['GET','POST']
    def get(self):
        return 'index get method'

    def post(self):
        return 'index post method'

app.add_url_rule('/index',view_func=IndexView.as_view(name='hello'))
if __name__ == '__main__':
    app.run()

从方法一的分析可知,在继承View的自定义视图类中必须要定义dispatch_request方法,在该方法中通过判断请求方式来实现相对应的功能。而在MethodView类中已经帮我们实现了dispatch_request。让我们一起来看一看MethodView的源码:

class MethodView(with_metaclass(MethodViewType, View)):
    
    def dispatch_request(self, *args, **kwargs):
        # self是自定义的视图类,判断来的请求方式请否允许并获取
        meth = getattr(self, request.method.lower(), None)
        if meth is None and request.method == "HEAD":
            meth = getattr(self, "get", None)

        assert meth is not None, "Unimplemented method %r" % request.method
        return meth(*args, **kwargs)  # 比如请求方式为get,到这里就是执行get()

(1)执行as_view()方法。其实还是调用的是View里的as_view,上面已经介绍过了,请求来了就执行dispatch_request方法

(2)在自定义类中没有dispatch_request方法,所以执行MethodView中的dispatch_request方法

(3)dispatch_request中判断了请求方式是否允许,以及执行请求

第二种方式已经帮我们封装好了请求分发的功能,所以是比较推荐的使用方式

上一篇:相机权限请求时,未在主线程的bug


下一篇:java事件队列事件调度刷新/陷阱事件