drf-解析器(reqeust.data)源码分析

203 阅读2分钟

drf-解析器(reqeust.data)

使用 request.data 获取请求体中的数据。

这个 reqeust.data 的数据怎么来的呢?其实在drf内部是由解析器,根据请求者传入的数据格式 + 请求头来进行处理。

from rest_framework.settings import api_settings
from rest_framework.negotiation import DefaultContentNegotiation
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser, FileUploadParser
​
class OrderView(APIView):
    # 所有的解析器
    # parser_classes = api_settings.DEFAULT_PARSER_CLASSES
    parser_classes = [JSONParser, FormParser, MultiPartParser]
    # 根据请求头,匹配对应的解析器;寻找渲染器
    # content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
    content_negotiation_class = DefaultContentNegotiation
​
    def get(self, request, *args, **kwargs):
        return Response('OK')

JSONParser (*)

image-20210827081058194

FormParser

image-20210827081244795

MultiPartParser(*)

image-20210827083047327

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:8000/test/" method="post" enctype="multipart/form-data">
    <input type="text" name="user" />
    <input type="file" name="img">
​
    <input type="submit" value="提交"></form>
</body>
</html>

FileUploadParser(*)

image-20210827084403453

解析器可以设置多个,默认解析器:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.parsers import MultiPartParser, JSONParser, FormParser
​
class UserView(APIView):
​
    def post(self, request):
        print(request.content_type)
        print(request.data)
​
        return Response("...")
​

源码分析()

①、请求进来,执行父类APIView类的dispatch方法

image-20220913094755332

②、self.initialize.request这个方法是APIView这个类的方法,这个函数返回一个Request的实例对象。

  • 第一行调用了一个get_parser_context方法
def initialize_request(self, request, *args, **kwargs):
    parser_context = self.get_parser_context(request)
​
    return Request(
        request,
        parsers=self.get_parsers(),
        authenticators=self.get_authenticators(),
        negotiator=self.get_content_negotiator(),
        parser_context=parser_context
    )

image-20220918222558664

③、进入get_parser_context方法本质是返回了一个字典

  • view:当前的视图对象
  • URL传过来的参数
  • parser_context={视图对象,URL路由参数}
def get_parser_context(self, http_request):
    return {
        'view': self,
        'args': getattr(self, 'args', ()),
        'kwargs': getattr(self, 'kwargs', {})
    }

④、回到②中parsers=self.get_parsers获取所有解析器类的对象列表

def get_parsers(self):
    return [parser() for parser in self.parser_classes]

⑤、回到②中negotiator=self.get_content_negotiator获取类的对象DefaultContentNegotiation()

def get_content_negotiator(self):
    if not getattr(self, '_negotiator', None):
        self._negotiator = self.content_negotiation_class()
        return self._negotiator

⑥、这时候再进去Request看看接受了这些参数后做了些什么操作

  • 将这几个参数接受到对象属性中
  • parser_context新增一个drf的request和encoding(编码)

image-20220918222951742

⑦、回到dispatch,最终走到执行反射视图函数,只有在视图函数中调用request.data才会触发解析的动作(多次调用也只会解析一次)

  • 反射取_full_data的值,若没有则接卸加载到_full_data
  • 若反射取到有这个值,直接返回_full_data的值
@property
def data(self):
    if not _hasattr(self, '_full_data'):
        self._load_data_and_files()
        return self._full_data

⑧、进入到self._load_data_and_files中,

  • 就是将解析到的数据加载到self._full_data
  • 主要看_parse干了哪些事

image-20220918224300156

image-20220918224955269

image-20220918220249124 image-20220918220349444