DRF之APIView和Request对象
View路径
from django.views.generic.base import View # 最真的路径 from django.views.generic import View # 因为在generic包的init里注册了 from django.views import View # views包的init里注册了
注:不管是DRF中的APIView还是什么xxView,最后只要继承了Django中的View就是视图类
APIView的执行流程
路由 path('order/', views.OrderView.as_view())---》第二个参数是函数内存地址---》APIView的as_view的执行结果---》本质还是用了View类的as_view内的view闭包函数,去掉了csrf认证----》当请求来了---》触发view闭包函数执行,并且传入request--->调用了self.dispatch-->self是视图类的对象,从OrderView中找dispatch,但是找不到----》父类APIView中有---》本质执行的dispatch是APIView----》
1、APIView的as_view方法
view = super().as_view(**initkwargs) # 调用APIView的父类(View)的as_view方法
return csrf_exempt(view) # 去掉csrf_exempt的认证,以后只要继承了APIView后,csrf就无效了,无论中间件是否注释掉
关于@csrf_exempt
crsf的局部禁用--》在视图函数上加装饰器---》csrf_exempt装饰器---》装饰器本质就是一个函数
@csrf_exempt # 装饰器的@ 是一个语法糖(特殊语法)-->把下面的函数当参数传入装饰器中并且把返回结果赋值给函数名:index=csrf_exempt(index)
def index(request) pass 跟 csrf_exempt(index) 一毛一样
2、APIView的dispatch
def dispatch(self, request, *args, **kwargs): # request是新的drf提供的request,它是由老的django的request得到的 # 通过老request,生成一个新request,drf的Request的对象 request = self.initialize_request(request, *args, **kwargs) # 把新的request,放到了视图类对象中 self.request = request try: # 执行了三大认证(认证,权限,频率) self.initial(request, *args, **kwargs) # self.http_method_names是个列表 if request.method.lower() in self.http_method_names: # 原来dispatch的核心代码 handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed # 原来dispatch写的,但是request已经不是老request了,是新的 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
APIView执行流程总结
1、包装了新的Request对象,以后视图类中的方法中传入的request对象都是新的
2、在进入视图函数之前,执行了三大认证
3、无论三大认证还是视图函数的方法,执行过程中出了异常,都会被处理掉
如何包装了新的request
# APIView中的dispatch方法处理老的request request = self.initialize_request(request, *args, **kwargs) # initialize_request方法,当前类(自己写的)没有去父类找,还是APIView def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) return Request( request, # 老的request,传入的非处理的,返回后就是新的了 parsers=self.get_parsers(), authenticators=self.get_authenticators(), negotiator=self.get_content_negotiator(), parser_context=parser_context ) 注意:上面返回的Request对象是rest_framework导入的,然后实例化后返回的,实例化就少不了__init__构造函数 from rest_framework.request import Request '''Request类''' class Request: # 这里即将要初始化的request是传入的老的request def __init__(self, request, parsers=None, authenticators=None,negotiator=None, parser_context=None): ··· # 初始化,将传入的老的request放入新的_request中,所以request._request是老的,self.request._request等价于request._request self._request = request ···
验证新老request
class Test(APIView): def get(self, request): data = {'status': 200, 'msg': 'success'} # 新的request print(type(request)) # <class 'rest_framework.request.Request'> print(type(self.request))# <class 'rest_framework.request.Request'> # 老的request print(type(self.request._request)) # <class 'django.core.handlers.wsgi.WSGIRequest'> print(type(request._request)) # <class 'django.core.handlers.wsgi.WSGIRequest'> return Response(data) 新的:<class 'rest_framework.request.Request'> 老的:<class 'django.core.handlers.wsgi.WSGIRequest'>
三大认证如何走
self.initial(request, *args, **kwargs)---》APIView的 核心代码: self.perform_authentication(request) # 认证 self.check_permissions(request) #权限 self.check_throttles(request) # 频率
# 如果用过新包装过的request来调用原来的方法呢?这样给使用者的感觉确实没什么变化源码如下: '''重写了getattr''' def __getattr__(self, attr): try: return getattr(self._request, attr) except AttributeError: return self.__getattribute__(attr) 重写getattr的结果是,新的request.method执行的时候本质是request._request.method执行了原来老的request的方法,通过这句getattr(self._request, attr)反射,所以才一样
总结:新的request当老的用即可,只是多了个data前端post请求传入的数据,三种编码格式都可以获取
验证处理三种编码格式
json格式,只有request.data可以获取,结果是字典
form-data格式和urlencode格式都可以获取并且是QueryDict对象
class OrderView(APIView): def get(self, request): return HttpResponse('get请求') def post(self, request): print(request.POST) print(request._request.POST) print(request.data) return HttpResponse('post请求')
结果
练习
原Django中没有request.data。写一个