django类视图中as_view()方法的源码分析

我们先来看这样一个示例:

先定义一个路由:

from django.urls import  path
from app import views as app_views

urlpatterns = [
    path('mine/', app_views.MyView.as_view(say_words="hello"), name='my-view'),

]

再定义一个视图函数:

from django.http import JsonResponse
from django.views import View


class MyView(View):
    say_words = None

    def get(self, request, *args, **kwargs):
        print('111')
        username = request.GET.get("username")
        password = request.GET.get('passpword')
        data = {
            'username': username,
            'password': password,
            'say_words': self.say_words,
        }
        print(username, password)
        return JsonResponse(data)

运行结果:

django类视图中as_view()方法的源码分析_第1张图片

 这段代码中:

  1. 类视图通过as_view() 调用。
  2. as_view()传入的参数say_words,是对于视图类中 say_words属性的重新赋值。
  3. get请求页面,as_view()方法,直接调用类视图中的get()方法。
  4.  Url请求中的参数,通过 request.GET.get()获取

你肯定很好奇,视图函数什么也没做,里头的get的方法就被调用了,自己的say_words参数平白无故就被重新赋值了。

为啥?

为了说清楚这个问题,我把源码抽出来进行了简化 。看下面这段代码:

class View:
    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)

    @classmethod
    def as_view(cls, **initkwargs): # 参数 say_words='hello'
        def view(*args, ):
            self = cls(**initkwargs)  # 创建类视图对象
            handler = getattr(self, 'get', None)  #  handler=self.get
            return handler(*args)  # self.get(),调用自己类的get()方法
        return view    # 返回view方法对象


class MyView(View):
    def get(self):
        print(self.say_words)

if __name__ == '__main__':
    MyView.as_view(say_words='hello')()

这一段代码,主要运用了继承和闭包函数的知识。调用父类的类方法as_view(),并在闭包函数里头实例话MyView本身,在实例化的时候调用父类的 __init__()方法,对属性重新赋值。闭包函数调用自己的get方法,实现对MyView中get方法的调用。

运行结果:

如果你看不懂,那我再简化。

class View:
    def __init__(self, say_words):
        self.say_words = say_words

    @classmethod
    def as_view(cls, say_words):
        self = cls(say_words)  # 创建类视图对象
        self.get()

class MyView(View):
    def get(self):
        print(self.say_words)


if __name__ == '__main__':
    MyView.as_view(say_words='hello')

这下应该明白了吧。本质就是继承加类方法中实例自己。非常巧妙,设计出这样代码的人真是天才啊。

有了上面的代码。我们接下来要做的,无非就是在这个基础上丰富。

1.更完备的数据校验。

2.请求带来的request.method,可能是get,也可能是post,怎们根据不同的方法调用不同的函数。

3.要加option方法,告诉我们这个视图函数都写了哪些请求方法。

好,带着这些问题,我们去看源码:

首先入口是MyView.as_view()。

MyView继承自View类,使用了父类的中的类方法as_view()()。

django类视图中as_view()方法的源码分析_第2张图片

这时候MyView中,具有的属性应该入下面所示,注意 __init__()方法还没有被调用,要在实例化对象时才被调用。

django类视图中as_view()方法的源码分析_第3张图片

接下来,到我们的关键了。as_view()方法才是入口,首先是对参数的检查。

django类视图中as_view()方法的源码分析_第4张图片 

 接下来,再看闭包函数view中都做了什么?

其实,view方法经历了以下几个流程:

  1. setup()
  2. dispatch()
  3. http_method_not_allowed()
  4. options()

django类视图中as_view()方法的源码分析_第5张图片

其中,dispatch根据request发来的method,调用视图函数中的不同方法:

django类视图中as_view()方法的源码分析_第6张图片

 如果请求方法异常,调用这个类。

django类视图中as_view()方法的源码分析_第7张图片

 optionss()方法告诉我们这个视图函数都支持那些请问方法。

django类视图中as_view()方法的源码分析_第8张图片

 至此,这段代码分析完了,有了这个基础,可以开心地去分析rest_framework中的Api'View视图函数了。

你可能感兴趣的:(python)