rest-framework之解析器

解析器

解析器的作用

根据请求头 content-type 选择对应的解析器对请求体内容进行处理。
有application/json,x-www-form-urlencoded,form-data等格式

  • 用来解析前台传过来的数据编码方式
    urlencoded:form表单:name=lqz&age=18
    formdata :上传文件:--dadfgdgag--
    json:json格式 {"name":"lqz"}

  • 解析器取的顺序
    1. 视图类中取
    2. django总settings里取
    3. drf默认的配置文件取

全局配置解析器

  • 全局配置

    在setting中:

REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES':[
        'rest_framework.parsers.JSONParser'
        'rest_framework.parsers.FormParser'
        'rest_framework.parsers.MultiPartParser'
    ]
}

路由:

urlpatterns = [
    url(r'test/', TestView.as_view()),
]

视图函数:

from rest_framework.views import APIView
from rest_framework.response import Response

class TestView(APIView):
    def post(self, request, *args, **kwargs):
        print(request.content_type)

        # 获取请求的值,并使用对应的JSONParser进行处理
        print(request.data)
        # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
        print(request.POST)
        print(request.FILES)
        return Response('POST请求,响应内容')

    def put(self, request, *args, **kwargs):
        return Response('PUT请求,响应内容')
  • 局部使用:
    在视图内部制定解析器名称
from rest_framework.parsers import JSONParser,MultiPartParser,FormParser
    parser_classes = [JSONParser,FormParser]
class TestView(APIView):
a. 仅处理请求头content-type为application/json的请求体
    parser_classes = [JSONParser, ]
b. 仅处理请求头content-type为application/x-www-form-urlencoded 的请求体
    parser_classes = [FormParser, ]
c. 仅处理请求头content-type为multipart/form-data的请求体
    parser_classes = [MultiPartParser, ]
d. 仅上传文件
    parser_classes = [FileUploadParser, ]
e. 同时多个Parser
当同时使用多个parser时,rest framework会根据请求头content-type自动进行比对,并使用对应parser
    parser_classes = [JSONParser, FormParser, MultiPartParser, ]
    
    def post(self, request, *args, **kwargs):
        print(request.content_type)

        # 获取请求的值,并使用对应的JSONParser进行处理
        print(request.data)

        # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
        print(request.POST)
        print(request.FILES)
        return Response('POST请求,响应内容')

    def put(self, request, *args, **kwargs):
        return Response('PUT请求,响应内容')
    

源码分析

在调用request.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._data, self._files = self._parse()

def _parse(self):
    #用户请求头里content_type的值
    media_type = self.content_type

    #self.parsers 就是用户配置的parser_classes =[FileUploadParser,FormParser ]
    #self里就有content_type,传入此函数
    parser = self.negotiator.select_parser(self, self.parsers)
    查看self.negotiator.select_parser(self, self.parsers)
     
def select_parser(self, request, parsers):
    #同过media_type和request.content_type比较,来返回解析器,然后调用解析器的解析方法
    #每个解析器都有media_type = 'multipart/form-data'属性
    for parser in parsers:
       if media_type_matches(parser.media_type, request.content_type):
            return parser
       return None
       
最终调用parser的解析方法来解析parsed = parser.parse(stream, media_type, self.parser_context)
Request实例化,parsers=self.get_parsers()
    Request(
                request,
                parsers=self.get_parsers(),
                authenticators=self.get_authenticators(),
                negotiator=self.get_content_negotiator(),
                parser_context=parser_context
            )
get_parsers方法,循环实例化出self.parser_classes中类对象
    def get_parsers(self):
        return [parser() for parser in self.parser_classes]   
        
self.parser_classes 先从类本身找,找不到去父类找即APIVIew 中的
    parser_classes = api_settings.DEFAULT_PARSER_CLASSES
api_settings是一个对象,对象里找DEFAULT_PARSER_CLASSES属性,找不到,会到getattr方法
        def __getattr__(self, attr):
            if attr not in self.defaults:
                raise AttributeError("Invalid API setting: '%s'" % attr)

            try:
                #调用self.user_settings方法,返回一个字典,字典再取attr属性
                val = self.user_settings[attr]
            except KeyError:
                # Fall back to defaults
                val = self.defaults[attr]

            # Coerce import strings into classes
            if attr in self.import_strings:
                val = perform_import(val, attr)

            # Cache the result
            self._cached_attrs.add(attr)
            setattr(self, attr, val)
            return val
user_settings方法 ,通过反射去setting配置文件里找REST_FRAMEWORK属性,找不到,返回空字典

@property
def user_settings(self):
    if not hasattr(self, '_user_settings'):
        self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})
    return self._user_settings
posted @ 2018-11-23 09:59 MAU 阅读(...) 评论(...) 编辑 收藏
Life will always knock us down, but we can choose whether to stand back up, then keep fighting. 生活会把我们打趴下,但我们可以选择重新站起来,继续奋斗。