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对象

posted @ 2022-04-22 23:34  JasonBorn  阅读(140)  评论(1编辑  收藏  举报