🍖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
- 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
@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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现