🍖APIView源码及Request对象分析

一.CBV源码分析

1.分析流程

CBV的源码分析在上一篇文章中做过详细介绍 👉点击传送:https://www.cnblogs.com/songhaixing/p/14583239.html

2.总结分析步骤

  • path的第二个参数是:View类的as_view内部有个view闭包函数内存地址
  • 一旦有请求来了,匹配test路径成功
  • 执行第二个参数view函数内存地址(requset)
  • 本质执行了self.dispatch(request)
  • 通过反射去获得方法 (假设是get方法) 的内存地址赋值给handler
  • 最后执行handler方法, 传入参数, 也就是触发了(get)方法的执行

二.APIView源码分析

与CBV的源码分析过成一样, 我们也是从路由中的as_view()方法入手

1.首先创建一个DRF类来逐步分析

  • views.py
from rest_framework.views import APIView
from rest_framework.response import Response

class DrfTestView(APIView):
    def get(self,request):
        print(type(request))
        print(type(request._request))
        print(request._request.method)
        print(request.method)
        return Response({'status':200,'msg':'成功!'})

    def post(self,request):
        print(request.POST)
        print(request.data)
        return Response('post测试')
  • urls.py
path('test/', views.DrfTestView.as_view()),

2.分别使用 get, post 方式测试输出结果

  • get 请求测试
print(type(request))
# <class 'rest_framework.request.Request'>
 
print(type(request._request))
# <class 'django.core.handlers.wsgi.WSGIRequest'>

print(request._request.method)  # GET
print(request.method)  # GET

img

  • post 请求测试
print(request.POST)  # <QueryDict: {}>
print(request.data)  # {'status': 400, 'msg': '失败!'}

img

3.疑问?

  • 为什么 Django的request对象会变成 DRF的request对象

  • 为什么 DRF 的request也能取出 Django中 request对象的属性

  • 原生的 request 对象去哪里了

4.分析流程

  • 点击路由层中配置的 as_view() 方法

img

ps : 装饰器函数的原理 csrf_exempt

@csrf_exempt
def test():
 pass

# 本质上就是将装饰器下方的函数当做参数传入
test=csrf_exempt(test)
  • 再去到父类 View 中看其源码

img

view 方法中最后返回了 dispatch方法, 属性的查找顺序, 先找自己, 再找父类, 所以先找到了自己(APIView)里面的 dispatch 方法

  • 查看 dispatch 方法里面的逻辑代码

img

我们可以发现 APIView 对 dispatch 方法进行了重写, 并且重写了不少内容

  • 使用 initialize_request 方法对原生 request 对象的封装
  • 认证、权限、频率控制
  • 处理全局异常
  • 处理全局响应
  • 我们在查看 initialize_request 方法如何进行封装

img

  • 继续点进 Request 查看

img

我们发现原生的 request 对象在 DRF的 request 中变成了 _request

  • 顺便看一下执行的 认证、权限、频率 (后边进行详细源码分析)

img

5.流程总结

  • 请求来了, 匹配路由成功执行了APIView类的 as_view( ) 方法其内部是用了父类View的as_view( ) 方法, 执行了 view 闭包函数
  • 但是加了个csrf_exempt装饰器,所以,继承了APIView的所有接口,都没有csrf的校验了
  • 按顺序查找dispatch方法, 想找自己, 再找父类, 结果自己里面重写了dispatch方法
  • 在APIView中的dispatch方法中先把原来request封装进去,变成新的 DRF的request对象
  • 接下来又执行了三个组件,分别是认证,权限和频率
  • 处理了全局异常
  • 再走分发方法,最后返回response

6.总结注意点

  • 所有的csrf都不校验了
  • request对象变成了新的request对象,drf的request对象
  • 执行了权限,频率,认证
  • 捕获了全局异常(统一处理异常)
  • 处理了response对象,如果浏览器访问是一个样,postman访问又一个样
  • 以后,在视图类中使用的request对象已经不是原来的request对象了,现在都是drf的request对象了

三.Request 对象分析

1.通过以上对 APIView 的分析:

  • Django原生request对象 : django.core.handlers.wsgi.WSGIRequest

  • DRF 的 request 对象 : rest_framework.request.Request

  • drf 的 request 对象中有原生的 request 对象 : self._request

img

2.疑问

  • 在视图类中使用 request 对象, 从中取出想要的数据
# 正常取值应该是使用 "_request"
request._request.method

# 但我们使用的却是
request.method

3.分析

  • 我们猜想一定是其中重写了点拦截方法 __getattr__

img

在 Response 类中找到 __getattr__, 当属性在 drf 中的 request 中找不到时, 就会通过反射的方式从原生的 request 对象中取值

所以虽然视图类中request对象变成了drf的request,但是用起来,跟原来的一样,只不过它多了一些属性

4.总结注意点

  • drf 的 request 对象用起来跟原来一样 (重写了__getattr__)
  • request.data : post请求提交的数据,不论什么格式,都在它中
  • requst.query_params : get请求提交的数据 (查询参数), 也可以直接使用 request.GET
posted @ 2021-04-17 13:15  给你骨质唱疏松  阅读(3735)  评论(0编辑  收藏  举报