本文探究Django以及DRF的视图的层层递进,从源码学习视图的不断完善和丰富
01 最简单的视图 FBV
urlpatterns = [
path('test01/', views.test01)
]
只要在浏览器上请求 http://127.0.0.1:8000/book/test01/
就可以看到 test01 被调用
需要注意的是,Django决定出发哪个视图函数或者方法的时候,跟请求的方法类型是没有关系的,请求的方法只是请求的参数而已,在FBV模式下,不管test01是什么请求方法都可以出发test01
02 视图类CBV
为什么会有视图类?
首先很多接口属于同一个模块,典型的就是对于数据的增删查改,其实是围绕同一个功能或者模块儿来实现的。另外我们经常将一个页面或者模块下的所有的接口集成到一个视图类中,方便管理,在视图类中,可能多个方法的部分代码具备高度相似性,因此可以抽取出来作为公共方法,给多个接口调用,因此视图类更方便开发和管理。
Django 中的视图类都需要继承 from django.views.generic import View
因为他有一个核心的方法 as_view方便调用
下面看一下视图的简单使用
class TestView(View):
def get(self, request):
print("调用了get方法")
return HttpResponse('TestView GET')
def post(self, request):
print("调用了get方法")
return HttpResponse('TestView POST')
def put(self, request):
print("调用了get方法")
return HttpResponse('TestView PUT')
urlpatterns = [
path('test01/', views.test01),
path('testview/', views.TestView.as_view())
]
通过postman分别使用 get,post,put方法测试一下
可以看到,只是在路由那里写了一个 views.TestView.as_view()
, django 程序就可以依据不同的请求方式映射到不同的函数上去执行。
这时 as_view 方法的功劳,接下来我们就去 as_view 方法中去一探究竟
as_view 方法被我单独复制出来,并且删减了一些注释,方便放在一张截图之中,as_view 的核心内容被我圈为3块。下面一块一块得解释
1:参数验证块儿
http_method_names
就是常见的网络请求方法
initkwargs
使我们调用 as_view 的时候传递的参数,as_view 是可以传递参数的,只是我们这里没传,这段代码校验参数是为了防止参数里面有内容覆盖了那些网络请求方法,为什么会这样,我们后面会解释,然后还校验了这些传递的参数必须是当前视图类存在的,不存在也会报异常
2:核心视图方法
view这个内部类是最核心的视图方法,
self = cls(**initkwargs)
是使用当前视图类构建了一个对象,并将传递给 as_view 的初始化参数传递给这个视图类对象
def setup(self, request, *args, **kwargs):
"""Initialize attributes shared by all view methods."""
if hasattr(self, "get") and not hasattr(self, "head"):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
setup方法干了什么事,如果当前对象有 get 属性,但是没有 head 属性的话,就让 head 属性指向 get 属性,同时将 request 这个网络请求对象赋值给 当前视图类对象了,args 和 kwargs 是网络请求传递的参数,例如我们经常看到这样的url
http://127.0.0.1:8000/book/test01/19/20/?name=张三
其中这个19和20可以通过url映射规则,提取为请求的参数,并放进 kwargs 中。这里我们可以尝试将 View 源码拷贝出来,然后在 setup 方法中打印 args 和 kwargs,最后让我们的自定义视图类集成拷贝出来的 View 类,就会出发setup 中的打印行为。当然这种行为在 java 中是不可能成功的, Java是强类型语言,而 python 是弱类型语言,鸭子类型,只要有同名方法,皆可以调用。
我对自定义视图类和 as_view 中的 setup 方法做了如下的改动
class TestView(View):
def get(self, request, pk1, pk2):
print(pk1, pk2)
print(self.request)
print(request)
print(self.kwargs)
print("调用了get方法")
return HttpResponse('TestView GET')
def setup(self, request, *args, **kwargs):
print(args, kwargs)
"""Initialize attributes shared by all view methods."""
if hasattr(self, "get") and not hasattr(self, "head"):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
path('testview/<int:pk1>/<int:pk2>/', views.TestView.as_view())
使用 postman 发起 get 请求,pycharm 控制台打印了如下内容
依据打印结果,可以发现,19和20分别被映射为 pk1 和 pk2,在Python代码中,def func(a,b,c=10)
这样的函数均可以使用 func(q=1,b=2,c=3) 来实现调用
另外 setup 函数将 request 对象和 kwargs 都赋给了视图类对象,因此在视图类中可以直接使用 self.request 和 self.kwargs 可以直接调用
事实证明 self.request 和传递给 get 的 request 是同一个对象,self.kwargs 也可以取用
紧接着 view 方法调用了 dispatch 方法,这个方法也是一个灵魂方法
dispatch 方法通过解析请求中的方法通过反射的方式获取自定义视图类中的和网络请求同名的方法。
因此 自定义视图类最后可能调用的方法必须是网络请求的那些方法名
3:返回这个 view 方法
因此CBV模式的本质还是 FBV,只是利用反射机制做了网络请求方法和视图类同名方法之间的映射
标签:架构,get,self,request,视图,DRF06,方法,view From: https://www.cnblogs.com/yaowy001/p/17041569.html