drf之解析器应用及源码分析

54 阅读1分钟

1.解析器概述

将前端传入的数据,根据请求头,匹配相应的解析器JSONParserFormParserMultiPartParserFileUploadParser,数据解析完成后赋值给request.data

2.解析器应用

from rest_framework.parsers import JSONParser, FormParser, MultiPartParser, FileUploadParser
from rest_framework.negotiation import DefaultContentNegotiation


class HomeView(APIView):
    # 所有的解析器
    # parser_classes = [JSONParser, FormParser]

    # 根据请求,匹配对应的解析器 ;  寻找渲染器
    # content_negotiation_class = DefaultContentNegotiation
    

    def post(self, request, *args, **kwargs):
        # 当调用request.data时就会触发解析的动作。
        print(request.data)  # {}
        print(request.data)  # QueryDict
        return Response("OK")

3.源码分析

class Request:
    def _parse(self):

        media_type = self.content_type
        try:
            stream = self.stream
        except RawPostDataException:
            if not hasattr(self._request, '_post'):
                raise
            if self._supports_form_parsing():
                return (self._request.POST, self._request.FILES)
            stream = None

        if stream is None or media_type is None:
            if media_type and is_form_media_type(media_type):
                empty_data = QueryDict('', encoding=self._request._encoding)
            else:
                empty_data = {}
            empty_files = MultiValueDict()
            return (empty_data, empty_files)

        parser = self.negotiator.select_parser(self, self.parsers)

        if not parser:
            raise exceptions.UnsupportedMediaType(media_type)

        try:
            parsed = parser.parse(stream, media_type, self.parser_context)
        except Exception:
            self._data = QueryDict('', encoding=self._request._encoding)
            self._files = MultiValueDict()
            self._full_data = self._data
            raise

        try:
            return (parsed.data, parsed.files)
        except AttributeError:
            empty_files = MultiValueDict()
            return (parsed, empty_files)
    
    def _load_data_and_files(self):
        if not _hasattr(self, '_data'):
            self._data, self._files = self._parse()
            if self._files:
                self._full_data = self._data.copy()
                self._full_data.update(self._files)
            else:
                self._full_data = self._data

            # if a form media type, copy data & files refs to the underlying
            # http request so that closable objects are handled appropriately.
            if is_form_media_type(self.content_type):
                self._request._post = self.POST
                self._request._files = self.FILES
    
    @property
    def data(self):
        if not _hasattr(self, '_full_data'):
            self._load_data_and_files()
        return self._full_data


class APIView(View):
    parser_classes = api_settings.DEFAULT_PARSER_CLASSES
    content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
    
    def get_content_negotiator(self):

        if not getattr(self, '_negotiator', None):
            self._negotiator = self.content_negotiation_class()
        return self._negotiator
    
    def get_parsers(self):
        return [parser() for parser in self.parser_classes]
    
    def get_parser_context(self, http_request):

        return {
            'view': self,
            'args': getattr(self, 'args', ()),
            'kwargs': getattr(self, 'kwargs', {})
        }
    
    def initialize_request(self, request, *args, **kwargs):

        parser_context = self.get_parser_context(request)

        return Request(
            request,    # django中的reqeust
            parsers=self.get_parsers(), # 获取所有解析器的对象

            negotiator=self.get_content_negotiator(),   # 根据请求匹配解析器
            parser_context=parser_context      # 视图对象、url参数
        )
    
    def dispatch(self, request, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        # 核心代码-->1 
        request = self.initialize_request(request, *args, **kwargs)

        self.initial(request, *args, **kwargs)
        
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
    
    
class HomeView(APIView):
    # 所有的解析器
    # parser_classes = [JSONParser, FormParser]

    # 根据请求,匹配对应的解析器 ;  寻找渲染器
    # content_negotiation_class = DefaultContentNegotiation

    def get(self, request, *args, **kwargs):
        print(request.version)
        print(request.versioning_scheme)
        # 反向生成URL: http://127.0.0.1:8000/api/v1/home/
        # url = request.versioning_scheme.reverse("hh", request=request)
        # print(url)
        return Response("...")

    def post(self, request, *args, **kwargs):
        # 当调用request.data时就会触发解析的动作。
        print(request.data)  # {}
        print(request.data)  # QueryDict
        return Response("OK")