Django类视图

为什么要用类视图

Django使用函数视图可以完成所有的业务开发,但是维护困难,更不利于扩展,通过继承和复用构建自己的视图并且复用代码,这就是类视图产生的原因,尤其是python支持多继承,可组合继承多个类,极大方便于扩展。

以函数的方式定义的视图称为函数视图(function base view FBV),函数视图便于理解。但是遇到一个视图对应的路径提供了多种不同HTTP请求方式的支持时,便需要在一个函数中编写不同的业务逻辑,代码可读性与复用性都不佳。

类视图(class base view CBV)

类视图的优点:代码可读性好、代码的复用性更高,如果其他地方需要用到类视图的某个特定逻辑,直接继承该类视图即可,而且可以重写父类的方法实现满足自己的业务需求。

类视图路由分发原理

路由配置

urlpatterns = [
    # 类视图(CBV)
    path('books/', views_class.BooksView.as_view())

]

http request请求到达路由之后,会交给views_class.BooksView.as_view()方法处理,看下这个方法的源码

class View:
    """
    Intentionally simple parent class for all views. Only implements
    dispatch-by-method and simple sanity checking.
    """

    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    def __init__(self, **kwargs):
        """
        Constructor. Called in the URLconf; can contain helpful extra
        keyword arguments, and other things.
        """
        # Go through keyword arguments, and either save their values to our
        # instance, or raise an error.
        for key, value in kwargs.items():
            setattr(self, key, value)

    @classonlymethod
    def as_view(cls, **initkwargs):
        """Main entry point for a request-response process."""
        for key in initkwargs:
            if key in cls.http_method_names:
                raise TypeError(
                    'The method name %s is not accepted as a keyword argument '
                    'to %s().' % (key, cls.__name__)
                )
            if not hasattr(cls, key):
                raise TypeError("%s() received an invalid keyword %r. as_view "
                                "only accepts arguments that are already "
                                "attributes of the class." % (cls.__name__, key))

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            self.setup(request, *args, **kwargs)
            if not hasattr(self, 'request'):
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
            return self.dispatch(request, *args, **kwargs)
        view.view_class = cls
        view.view_initkwargs = initkwargs

        # take name and docstring from class
        update_wrapper(view, cls, updated=())

        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())
        return view

可以看到as_view()方法最后返回了view方法的引用,也就是返回了view方法,在view方法里调用self.dispatch(request, *args, **kwargs)方法,进入该方法看下它的实现

    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

如果请求方法名小写在self.http_method_names列表(八种http请求类型)里,那么拿到视图类中方法名==请求方法名小写的方法赋予handler,也就是说如果是get请求,该请求会被视图中名称为get方法拦截并处理。

 

posted @ 2021-07-30 13:34  wang_longan  阅读(330)  评论(0编辑  收藏  举报