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对象分析(新的request)

  rest_framework.request.Request ---》常用属性和方法

  request.data

    前端post请求传入的数据---》在老的request.POST-->老的只能处理urlencoded和formdata编码格式,json格式不能处理---》无论前端用什么编码post提交的数据,都从data中获取

  request.files 

     上传的文件对象

# 如果用过新包装过的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。写一个

 

posted @ 2022-03-30 09:09  那就凑个整吧  阅读(139)  评论(0编辑  收藏  举报