zoukankan      html  css  js  c++  java
  • 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
    
  • 相关阅读:
    MySQL 列子查询及 IN、ANY、SOME 和 ALL 操作符的使用
    MySQL 标量子查询
    MySQL 子查询(subquery)语法与用法实例
    如何上传本地音乐获取MP3外链(欢迎分享和转载)
    RabbitMQ与Kafka的区别及其简单原理实现
    MySQL中varchar和char的区别
    MySQL降低insert, update, delete的优先级来优化性能
    Eclipse代码自动提示
    Java生成XML文件
    Java读取XML文件
  • 原文地址:https://www.cnblogs.com/polly-ling/p/10005783.html
Copyright © 2011-2022 走看看