27 APIView源码及Request对象分析

166次阅读
没有评论

共计 2616 个字符,预计需要花费 7 分钟才能阅读完成。

一.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

27 APIView 源码及 Request 对象分析

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

27 APIView 源码及 Request 对象分析

3. 疑问?

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

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

  • 原生的 request 对象去哪里了

4. 分析流程

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

27 APIView 源码及 Request 对象分析

ps : 装饰器函数的原理 csrf_exempt

```python
@csrf_exempt
def test():
pass

本质上就是将装饰器下方的函数当做参数传入

test=csrf_exempt(test)
```

  • 再去到父类 View 中看其源码

27 APIView 源码及 Request 对象分析

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

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

27 APIView 源码及 Request 对象分析

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

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

27 APIView 源码及 Request 对象分析

  • 继续点进 Request 查看

27 APIView 源码及 Request 对象分析

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

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

27 APIView 源码及 Request 对象分析

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

27 APIView 源码及 Request 对象分析

2. 疑问

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

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

3. 分析

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

27 APIView 源码及 Request 对象分析

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

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

4. 总结注意点

  • drf 的 request 对象用起来跟原来一样 (重写了__getattr__)
  • request.data : post 请求提交的数据,不论什么格式,都在它中
  • requst.query_params : get 请求提交的数据 (查询参数), 也可以直接使用 request.GET
正文完
 
shawn
版权声明:本站原创文章,由 shawn 2023-06-16发表,共计2616字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)