django的as_view方法源码实现分析

django的as_view方法源码实现分析


django的类视图拥有 自动查找指定方法的功能, 源码是通过 as_view()方法实现。

urls.py

from meduo_mall.demo import views

urlpatterns = [
    url(r'register/$', views.Demo.as_view())
]

views.py

from django.views.generic import View


class Demo(View):

    def get(self, request):
        return HttpResponse('get page')

    def post(self, request):
        return HttpResponse('post page')

为什么as_view能自动匹配指定的方法,先看源码:

@classonlymethod
    def as_view(cls, **initkwargs):  # 实际上是一个闭包  返回 view函数
        """
        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):  # 作用:增加属性, 调用dispatch方法 
            self = cls(**initkwargs)  # 创建一个 cls 的实例对象, cls 是调用这个方法的 类(Demo)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request  # 为对象增加 request, args, kwargs 三个属性
            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

    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        if request.method.lower() in self.http_method_names:  # 判断请求的方法类视图是否拥有, http_method_names=['get', 'post']
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)  # 如果存在 取出该方法
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)  # 执行该方法

简化版

@classonlymethod
    def as_view(cls, **initkwargs):  # 实际上是一个闭包  返回 view函数
        """
        Main entry point for a request-response process.
        """
        def view(request, *args, **kwargs):  # 作用:增加属性, 调用dispatch方法 
            self = cls(**initkwargs)  # 创建一个 cls 的实例对象, cls 是调用这个方法的 类(Demo)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request  # 为对象增加 request, args, kwargs 三个属性
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs)  # 找到指定的请求方法, 并调用它

        return view

    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        if request.method.lower() in self.http_method_names:  # 判断请求的方法类视图是否拥有, http_method_names=['get', 'post']
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)  # 如果存在 取出该方法
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)  # 返回该请求方法执行的结果

再简化

def as_view(): # 校验 + 返回view方法
    # 一些校验
    ...
    def view(): # 执行视图
        # 增加 为对象request, args, kwargs 属性
        ...
        return dispatch() # 调用指定的请求方法
    return view

def dispatch(): # 真正的查找指定的方法, 并调用该方法
    ...
    return handler()

调用顺序: as_view --> view --> dispatch

  • 可以看出as_view实际上是一个闭包, 它的作用做一些校验工作, 再返回view方法。
  • view方法的作用是给请求对象补充三个参数, 并调用 dispatch方法处理。
  • dispatch方法查找到指定的请求方法, 并执行.
    可以得出结论: 实际上真正实现查找的方法是 dispatch方法

原文章链接:https://www.jianshu.com/p/17860becea09
希望有一天我也可以写出这么短小精干的文章。

你可能感兴趣的:(Django)