django CBV视图源码分析

典型FBV视图例子

url路由系统

from django.conf.urls import url
from django.contrib import admin
from luffycity.views import BookView, AuthorView, PublisherView

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^book/', BookView.as_view()),
    url(r'^author/', AuthorView.as_view()),
    url(r'^publisher/', PublisherView.as_view()),
]

可以看到url系统拿到url后就去执行了视图函数的as_view()方法,那么这个方法到底做了什么事,我们先来看视图编写部分
视图系统

class BookView(views.View):
    def get(self,request):
        ret = Book.objects.all().values('title', 'publisher__name', 'author__name')
        l = {}
        for index, i in enumerate(ret):
            l[index] = i
            print(index,i)
        return JsonResponse(l)


class PublisherView(views.View):
    def get(self,request):
        ret = Publisher.objects.all().values('name','address')
        print(ret)
        l = {}
        for i, index in enumerate(ret):
            l[i] = index
        return JsonResponse(l)


class AuthorView(views.View):
    def get(self,request):
        ret = Author.objects.values('name','country','age')
        l = {}
        for i, index in enumerate(ret):
            l[i] = index
        print(l)
        return JsonResponse(l)

大家知道,我们编写的CBV的视图类中是没有as_view方法的,所以as_view肯定是我们视图类继承的view.View类中的方法,我们接下来分析下源码

View源码分析

我们进去view源码看看

找到as_view方法

    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("You tried to pass in the %s method name as a "
                                "keyword argument to %s(). Don't do that."
                                % (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)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            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方法

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs)

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.
        // 判断请求的方法是否在http_method_names中http_method_names是包含允许请求方式的八大请求
        if request.method.lower() in self.http_method_names:
           // 然后判断类视图中是否有请求对应的方法例如get,否则执行报错
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

总结

CBV源码步骤:
1、执行as_view方法,返回一个view函数,
2、路由系统会执行view函数,会调用dispatch函数
3、dispatch函数会根据requesrt.method请求的方法判断请求是否合理
4、请求合理后会去判断请求对应的方法是否在视图函数类中
5、执行相应的视图函数类的方法,例如请求方式为get,那么dispatch方法的返回就会执行视图的get方法

posted @ 2018-12-12 14:43  Kingfan  阅读(127)  评论(0编辑  收藏  举报