DRF基本使用及执行流程分析 | APIView源码分析
DRF基本使用及执行流程分析
介绍:
# 使用的都是CBV的方式 ,继承的类为drf提供的类(提供的类很多)
# 这里目前继承使用APIView类
# 因为APIView是所有类的基类,其他类可能拓展了方法后续会介绍。
基本使用:
对比Django来看他们的区别。
# 路由层:这里编写和django的CBV编写方式完全一样
urlpatterns = [
path('book2/',views.BookAPIView.as_view()),
]
# 拓展:
第二个参数的结果一定是一个函数的内存地址
当请求来的时候会给第二个参数加括号调用并且传一个参数为request
# 视图层:这里继承的类使用drf提供的类为APIView
# 我们在使用Django编写CBV的时候继承的是View
# drf中,自定义了Response类,以后给前端响应都用它,(而django会用HttpResponse,JsonResponse,render,redicet四大响应类)
from rest_framework.views import APIView
from rest_framework.response import Response
class BookAPIView(APIView):
def get(self,request,*args,**kwargs):
return Response('get请求')
# 总结:对比django只是继承的类不一样和返回的不一样
验证响应结果:
# drf的响应给前端的即是Response封装后响应的结果。
# 这个页面的渲染是drf自己封装的模板。
APIView的执行流程(源码分析)
引子:
在了解APIView执行流程需要简单的了解一下CBV源码分析View的执行流程:
地址:https://www.cnblogs.com/garyhtml/p/15955229.html
开始:
1.路由层:
urlpatterns = [
path('book2/',views.BookAPIView.as_view()),
]
# 如果有请求来访问book2/的路由,就会执行BookAPIView.as_view(),他的结果一定是一个函数的内存地址然后会自动加括号调用该函数,并将request参数传入
# 那么此时执行as_view()就去自己定义的类中BookAPIView查找该方法。
2.查找as_view()方法
# 视图层:
from rest_framework.views import APIView
from rest_framework.response import Response
class BookAPIView(APIView):
def get(self,request,*args,**kwargs):
return Response('get请求')
# 显然:我们自己定义的类中没有该方法,那么就去继承的APIView中查找
# 我们可以看到在APIView中重写的as_view方法,并且它继承的原来Django的View(所以不基于Django是用不了的)
# 那么此时as_view()方法已经不是View的as_view()方法了,我们来研究重写的这个as_view()方法是怎么编写的
上述:csrf_exempt(view)
相当于:
@csrf_exempt
def view():
...
# 这样就取消了csrf的保护
# 所以重写的as_view()方法目的只是为了取消csrf中间件的校验。
3.执行View的as_view()方法
# 此时super().as_view(**initkwargs)调用了父类的as_view()方法
# 所以:还要执行:APIView父类View的as_view方法
4.APIView的dispatch方法
# 去APIView中查找dispatch方法:
# 补充快速查找的方法:
# 我们看到在APIView中重写了dispatch方法,那么肯定执行APIView的dispatch。
# 接下来我们就来研究一下APIView中的dispatch方法
5.initialize_request方法
# 我们看到initialize_request的执行,执行结果是Request类序列化的结果,那么上述新的request即为Request序列化产生的对象,并且将老的request传给了这个类,还额外添加了一些功能属性。(这个Request是drf的类)
6.Request类
# 我们看到当Request类加括号时触发内部的__init__方法时,老的request赋值给了self._request,此时self时Request类的对象,那么就是新的request对象,
所以:新的request._request=老的request
7.验证request._request=request
# 实验:request._request=request是否正确
# 如下:
# 我们看到确实老的request是封装到的request._request中
# 新的request确实是Request实例化产生的对象
# 那么为什么新的request.GET也可以取到老的request._request.GET相同的结果呢我们来研究一下?
8.重写__getattr__方法
# 补充:
# 对象.属性或者方法的时候会自动触发当前所在类中内部的__getattr__魔法方法
# 魔法方法:不需要主动调用,在某种特定条件下就会自动触发它的执行
# 魔法方法的格式:编写在类中格式:__名字__
所以说:此时request.GET就会触发当前所在类Request类的__getattr__方法的执行
# 研究Request中(__getattr__)方法
# 如果新的request.属性没有该属性的话,就会执行__attr__将属性传入给参数attr
# 那么原因就找到了:Request中重写的这个__getattr__方法,还是去request._request把attr反射出来,所以还是走的request._request.GET
request:data属性
# 新的request中有一个新的属性 :data
- data是post请求携带的数据,返回结果为字典的形式
- 在django中我们知道不同的编码格式,存储在不同的方法中
如:request.POST取urlencoded编码格式的数据
request.body取json格式二进制数据
- 那么在drf中,无论什么编码格式,只要是post提交的数据,都在request.data中
# 文件对象还是在request.FILES
# 示例:
def post(self,request,*args,**kwargs):
print(request.data)
print(request.POST)
return Response('post请求')
总结加补充:APIView和Request对象分析
1 以后如果使用了drf,继承APIView(drf提供了很多view,他们都是继承自APIView),执行流程如下:
-包装出了一个新的request,在视图函数中使用时,跟原来没有区别
-注意:取post提交的数据,不要从request.POST中取了,要从request.data中取
-注意:取get提交的数据,尽量不从request.GET中取了,要从request.query_params中取
# 补充:
# query_params方法:
@property # 将方法封装成数据属性
def query_params(self):
return self._request.GET
2 Request类(drf的)中需要掌握的
-request.data # 方法包装成了数据属性
-request.query_params # 就是request._request.GET
-request.FIELS # 上传的文件
-用起来跟原来一样
3 APIView类
-包装新的request
-执行了认证,权限,频率....
-处理了全局异常
-包装了response对象