在Flask中和Django一样有两种视图模式,一种是基于函数,一种是基于类。下面来讨论一下Flask的CBV模式。
首先,说明一下flask视图函数注册路由的本质:
其实,route装饰器内部也是通过调用add_url_rule()方法实现的路由注册,只是route装饰器看起来更加美观,
源码的route函数,如下
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop("endpoint", None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
下面我们来看一下CBV的书写方式:
class Login(views.MethodView):
def get(self):
return "hello"
app.add_url_rule("/",view_func=Login.as_view("login"))
#view_func是add_url_rule(rule, endpoint, f, **options),的第三个参数f
要使用定义的视图类,必须要继承了MethodView,这个类继承了View类和MethodViewType类,内部封装了我们需要的功能
class MethodView(with_metaclass(MethodViewType, View)):
下面我们看一下as_view方法,
def as_view(cls, name, *class_args, **class_kwargs):
"""Converts the class into an actual view function that can be used
with the routing system. Internally this generates a function on the
fly which will instantiate the :class:`View` on each request and call
the :meth:`dispatch_request` method on it.
The arguments passed to :meth:`as_view` are forwarded to the
constructor of the class.
"""
def view(*args, **kwargs):
self = view.view_class(*class_args, **class_kwargs)
return self.dispatch_request(*args, **kwargs)
if cls.decorators:
view.__name__ = name
view.__module__ = cls.__module__
for decorator in cls.decorators:
view = decorator(view)
# We attach the view class to the view function for two reasons:
# first of all it allows us to easily figure out what class-based
# view this thing came from, secondly it's also used for instantiating
# the view class so you can actually replace it with something else
# for testing purposes and debugging.
view.view_class = cls
view.__name__ = name #view.__name__ = "login"
#view是上面定义的函数,函数名.__name__就是这个函数的函数名,
#这里我们就当于重新赋值了view这个函数的函数名
view.__doc__ = cls.__doc__
view.__module__ = cls.__module__
view.methods = cls.methods
view.provide_automatic_options = cls.provide_automatic_options
return view
经过上面对as_view的分析,我们知道,as_view返回了一个名字叫login的函数,然后开始进入add_url_rule方法,
def add_url_rule(
self,
rule,
endpoint=None,
view_func=None,
provide_automatic_options=None,
**options
):
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func)
options["endpoint"] = endpoint
methods = options.pop("methods", None)
刚开始endpoint为空,所以,进入if条件,执行_endpoint_from_view_func,
def _endpoint_from_view_func(view_func):
"""Internal helper that returns the default endpoint for a given
function. This always is the function name.
"""
assert view_func is not None, "expected view func if endpoint is not provided."
return view_func.__name__
我们看到_endpoint_from_view_func返回了函数的名字,执行if条件内的语句后,
就得到了,endpoint=函数名,所以endpoint和view_func=Login.as_view(“login”)中的login名字是一样的。
总结来说,Flask的CBV本质上和FBV是一样的,都是执行add_url_rule方法,主要就是使用形式上的不同
个人理解如上,如有错误欢迎指出,一定改正,共勉。
参考文章:https://blog.csdn.net/m0_37519490/article/details/80608365