共计 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
- post 请求测试
print(request.POST) # <QueryDict: {}>
print(request.data) # {'status': 400, 'msg': '失败!'}
3. 疑问?
-
为什么 Django 的
request
对象会变成 DRF 的request
对象 -
为什么 DRF 的
request
也能取出 Django 中request
对象的属性 -
原生的
request
对象去哪里了
4. 分析流程
- 点击路由层中配置的
as_view()
方法
ps : 装饰器函数的原理 csrf_exempt
```python
@csrf_exempt
def test():
pass本质上就是将装饰器下方的函数当做参数传入
test=csrf_exempt(test)
```
- 再去到父类 View 中看其源码
在
view
方法中最后返回了dispatch
方法, 属性的查找顺序, 先找自己, 再找父类, 所以先找到了自己 (APIView) 里面的dispatch
方法
- 查看
dispatch
方法里面的逻辑代码
我们可以发现 APIView 对
dispatch
方法进行了重写, 并且重写了不少内容
- 使用
initialize_request
方法对原生request
对象的封装- 认证、权限、频率控制
- 处理全局异常
- 处理全局响应
- 我们在查看
initialize_request
方法如何进行封装
- 继续点进
Request
查看
我们发现原生的
request
对象在 DRF 的request
中变成了_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
2. 疑问
- 在视图类中使用
request
对象, 从中取出想要的数据
# 正常取值应该是使用 "_request"
request._request.method
# 但我们使用的却是
request.method
3. 分析
- 我们猜想一定是其中重写了点拦截方法
__getattr__
在 Response 类中找到
__getattr__
, 当属性在 drf 中的 request 中找不到时, 就会通过反射的方式从原生的 request 对象中取值所以虽然视图类中 request 对象变成了 drf 的 request,但是用起来,跟原来的一样,只不过它多了一些属性
4. 总结注意点
- drf 的 request 对象用起来跟原来一样 (重写了
__getattr__
) request.data
: post 请求提交的数据,不论什么格式,都在它中requst.query_params
: get 请求提交的数据 (查询参数), 也可以直接使用request.GET