APIView与Request源码分析

APIView与Request

基于APIView+JsonResponse编写接口

from rest_framework.views import APIView
from django.http import JsonResponse
from .models import Book
# 以前我们继承的是django原生的view现在继承drf的APIView
class BookView(APIView):
    def get(self,request):
        books = Book.objects.all()
        book_list = []
        for book in books:
        	book_list.append({'name':book.name,'price':book.price})
        return JsonResponse(book_list,safe=False)
发现按照原本继承原生view的逻辑写法也可以正常编写 

基于APIView+Response编写接口

from rest_framework.views import Response
按照上面的代码最后一句return改成
return Response(book_list) 
# 不设置safe参数   字典和列表都可以序列化

​ 经过上面的流程体会到了APIView 与Response的方便快捷,但是不知道其底层都干了些什么事情,想要了解还得去查源码

APIView的源码分析

1.经过路由层的匹配成功自动执行'views.BookView.as_view()() '我们发现因为我们继承的是'APIView'这个类,此时会进入'APIView'里查看是否有'as_view'方法,进入查看是有的。而且是绑定给类的方法。
def as_view(cls, **initkwargs):
    # 发现其内部super使用子类调用父类方法,因为APIView继承的是原生View,那就是调用了django原生的as_view方法。返回的是as_view内层函数view
    "此时的view就是原生django as_view的内层函数view"
	view = super().as_view(**initkwargs)
    # csrf_exempt 就是排除了所有的csrf认证,把view传过去那么相当于给view加了个语法糖,view内部所有的方法都不用过csrf认证
 "我们在执行视图类的各种请求方法其实都是通过了view的内部进行了反射拿到并执行"
   return csrf_exempt(view)
2. 路由匹配成功后执行了上面的步骤最后'diango原生的view方法'返回的是'self.dispatch'方法. 我们通过名称空间的查找顺序此时的'self对象'是视图类'BookView'的对象那么我们先从自身查找发现并没有'dispatch'方法,那么去父类'APIView'里查找发现有这个方法,此时执行的是'APIView的dispatch'方法。
def dispatch(self, request, *args, **kwargs):
   	  # 此时的request还是django原生的request,从下面这行代码包装后成为了drf的新的request,“initialize_request”反回了一个新的request
       # 老的request被initialize_request方法内部的Response给了对象self._request
       request = self.initialize_request(request, *args, **kwargs)
       # 把新的request给了视图类BookView的对象
       self.request = request
       try:
           "initial 三大认证【认证,频率,权限】"# 此时的request是新的request
           self.initial(request, *args, **kwargs)   
           # 用反射拿到方法与原生的dispatch方法一致
           if request.method.lower() in self.http_method_names:
               handler = getattr(self, request.method.lower(),
                             self.http_method_not_allowed)
           else:
               handler = self.http_method_not_allowed
           # 新的request传入了视图方法此时视图类方法的request也是新的。
           response = handler(request, *args, **kwargs)
       except Exception as exc:
           # 在执行3大认证和视图类中方法的过程中,如果出了异常,都能捕获到---》全局异常捕获
           response = self.handle_exception(exc)			
       self.response = self.finalize_response(request, response, *args, **kwargs)
       return self.response

总结

1.祛除了所有的csrf认证
2.包装了新的request并传给了视图类,视图类中的request都是新的,不再是原生的。
3.执行视图类的方法前执行了三大认证
4.如果三大认证与视图类的方法执行过程报了错,都会被异常捕获--全局异常捕获
5.以后视图类的request都是新的。

Resquest源码分析

我们知道经过APIView类的各种方法处理后此时视图类的request是新的,那么老的request去哪里了。

在APIView里发现
from rest_framework.request import Request 
就是在dispatch内的initialize_request把request包装成了新的request,返回的Request,并在内部把老的给了self._request.那么此时新的request里面包含了老的request
request._request也能拿到老的。

此时又出现问题了,在视图类方法中执行request.method,研究源码发现新的Request他并没有method方法,但是有一个双下getattr方法,这个魔法方法在.一个不存在的名字时会触发。

    def __getattr__(self, attr):
        try:
            # self._request此时去了老的request反射拿到方法
            return getattr(self._request, attr)
        except AttributeError:
            return self.__getattribute__(attr)
        
request.data # data方法被伪装成了数据属性 不用加括号直接就可以的调用

	"POST,PUT等等请求方法在body内提交的数据,都从request.data中取,取出来就是字典,无论是哪种编码格式"
 
request.query_params # 也是被伪装成了方法
 	"get请求携带的参数都从这里面取"

request.FILES # 伪装了
	"前端提交过来的文件,从这里面取"

总结

1.新的request用起来与老的一样,新的取不到方法会从老的里面取
2.request.data 只要是在body内的数据都从这里取,取出来就是字典。不论编码请求方式
3.request.query_params 就是原来的request._request.GET
4.上传的文件从 request.FILES里取
posted @ 2023-02-01 16:38  李阿鸡  阅读(23)  评论(0编辑  收藏  举报
Title