我们先来看这样一个示例:
先定义一个路由:
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)
运行结果:
这段代码中:
你肯定很好奇,视图函数什么也没做,里头的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()()。
这时候MyView中,具有的属性应该入下面所示,注意 __init__()方法还没有被调用,要在实例化对象时才被调用。
接下来,到我们的关键了。as_view()方法才是入口,首先是对参数的检查。
接下来,再看闭包函数view中都做了什么?
其实,view方法经历了以下几个流程:
其中,dispatch根据request发来的method,调用视图函数中的不同方法:
如果请求方法异常,调用这个类。
optionss()方法告诉我们这个视图函数都支持那些请问方法。
至此,这段代码分析完了,有了这个基础,可以开心地去分析rest_framework中的Api'View视图函数了。