CBV、APIView源码分析
一、CBV源码分析
1、功能需求
基于类的视图---> 使用类编写---> 在类中写跟请求方式(methon)同名的方法---> 路由配置 类名.as_view()
前端的请求过来,什么请求,就会执行跟请求方式同名的方法
2、执行流程
路由匹配成功---> 配置在路由上的第二个参:执行函数内存地址自动加(request)---> 执行view(request)---> 执行了self.dispatch --->BookView没有---> 找到了父类View---> dispatch--->
handler = getattr(self, 'get') 反射 ---> return handler(request, *args, **kwargs)
3、源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # View.as_view的源码 @classonlymethod def as_view( cls , * * initkwargs): # 闭包函数 def view(request, * args, * * kwargs): self = cls ( * * initkwargs) # 类实例化得到对象:BookView的对象 # 调用对象的绑定方法 dispath---》去BookView中找dispatch--》找不到去父类---》View中的dispatch return self .dispatch(request, * args, * * kwargs) # 对象的方法 return view # 执行:BookView.as_view()(request)---》本质是执行 View中as_view内部的view方法,传入了reuqest----》在执行View的dispatch方法,传入了request # 看 :View.dispatch---》源码 def dispatch( self , request, * args, * * kwargs): if request.method.lower() in self .http_method_names: # 判断请求方式是否在那个固定的列表中[get, post...]---> # 反射:通过字符串 动态的 操作对象的属性或方法 # 假设是get请求---》去BookView中取出 get方法赋值给handler handler = getattr ( self , request.method.lower(), self .http_method_not_allowed) else : handler = self .http_method_not_allowed # 执行handler加括号,传入了request # 本质是执行 get(request) return handler(request, * args, * * kwargs) |
二、APIView源码分析
1、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #1 使用drf,以后都写cbv---> 继承一个视图类---> 以后都继承drf提供 的APIView #2 APIView 继承了djagno的View #3 补充:这三个都是一个 from django.views import View from django.views.generic import View from django.views.generic.base import View # 4 继承APIView写cbv---> 执行起来跟之前效果一样---> 内部发生了非常大的变化 1 写视图类 from rest_framework.views import APIView class PublishView(APIView): def get( self , request): return JsonResponse({ 'code' : 999 }) 2 配置路由 path( 'publish/' , PublishView.as_view()), |
2、执行流程
1 2 3 4 | 路由匹配成功 - - - 》BookView.as_view() - - - >APIView的as_view配置在路由上的第二个参:执行函数内存地址(request) - - - 》执行View的view(request) - - 》但是它去除了csrf认证 - - - 》dispatch - - - 》APIView的dispatch - - - 》 1 包装了新的request - - - 》视图类的方法中的request是新的 2 执行三大认证 3 处理了全局异常 |
补充:
当流程来到View的view(request)时,这里是已去掉csrf验证的view,view闭包函数中会调用self.dispatch。这里的self是一个具体的对象,比如BookView。不能再直接点跳转,需要从根上BookView类开始找,---》APIview中找到
3、源码分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | # 比之前继承django的View多了如下 - 0 去除了csrf认证 - 1 包装了新的request - 2 执行了认证,频率,权限 这三大认证 - 3 全局异常处理:在视图类的方法中执行报错,会被异常捕获,做统一处理 # 执行流程分析 - 请求来了 - - - 》执行PublishView.as_view()(request) - - - >PublishView类没有as_view - - - 》找父类 - - - 》APIView的as_view - APIView的as_view - - - 》本质在禁用csrf认证 @classmethod def as_view( cls , * * initkwargs): # 调用父类的as_view得到返回值赋值给view---》django的View的as_view【看过】---》返回View的as_view的闭包函数 view view = super ().as_view( * * initkwargs) # 现在这个view就是原来看的View的as_view的view # 去除了csrf认证----》局部禁用csrf---》在视图函数上加 装饰器csrf_exempt # 加了装饰器的本质: 被装饰的函数=装饰器(被装饰的函数) return csrf_exempt(view) - PublishView.as_view()(request) - - 》执行了禁用掉csrf的View的as_view的view - - - 》 self .dispath - - - >APIView的dispath def dispatch( self , request, * args, * * kwargs): # 1 包装了新的request对象 request = self .initialize_request(request, * args, * * kwargs) # 把新的request,赋值给了 self.request # self 是 PublishView的对象 self .request = request try : # 2 执行了3大认证 self .initial(request, * args, * * kwargs) ######开始### 跟之前View的dispath是一样的---》根据请求方式执行类中同名方法 ###执行视图类的方法 if request.method.lower() in self .http_method_names: handler = getattr ( self , request.method.lower(), self .http_method_not_allowed) else : handler = self .http_method_not_allowed response = handler(request, * args, * * kwargs) ######结束### # 执行三大认证和视图类的方法,如果出了异常,抛了错,会被捕获,统一处理 except Exception as exc: response = self .handle_exception(exc) self .response = self .finalize_response(request, response, * args, * * kwargs) return self .response # 装饰器的本质 @auth # add=auth(add)-->以后调用add 实际上调用 auth(add)() def add(): pass add = auth(add) ### 包装新的request # 1 request.data:前端传入的数据(post,put,编码格式)--->写到在请求体中的数据,都用 # 2 老request中有 request.GET 新的使用request.query_params 充当 # 3 其他的所有属性方法,用起来跟之前一样 ### 三大认证 self .perform_authentication(request) self .check_permissions(request) self .check_throttles(request) ### 处理了全局异常,统一处理了 |
补充:
1 self.request = request 封装了新的request后赋值给调用对象的request。
在视图函数中打印: <rest_framework.request.Request: POST '/books/'>
2 三大认证
self.initial(request, *args, **kwargs)
1 2 3 | self .perform_authentication(request) # 认证 self .check_permissions(request) # 权限 self .check_throttles(request) # 频率 |
4、 APIview总结:
视图类继承APIView视图类之后,多了
-0 去除了csrf认证
-1 新的request
-request.data
-request.query_params
-request.其他跟之前一样
-request._request 是老的
-2 三大认证
-3 全局异常