• 解析模块


    解析模块

    drf的解析模块(了解) - 服务的对象是数据包数据
    1、可以在视图类中通过parser_classes类属性对该视图的数据包解析做配置 - 局部配置
    2、可以在项目的配置文件的drf配置中通过DEFAULT_PARSER_CLASSES对该视图的数据包解析做配置 - 全局配置

    核心:请求的数据包格式会有三种(json、urlencoded、form-data),drf默认支持三种数据的解析,可以全局或局部配置视图类具体支持的解析方式

    用法

    ,系统默认三种都是支持的,主要是设置用户请求的数据包,进行配置,要求只要一种数据,方便使用。

    解析器的作用

    根据请求头 content-type 选择对应的解析器对请求体内容进行处理。

    有application/json,x-www-form-urlencoded,form-data等格式

    全局使用解析器

    • settings.py配置
    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES': [
            'rest_framework.parsers.JSONParser',
            'rest_framework.parsers.FormParser',
            'rest_framework.parsers.MultiPartParser',
        ],
    }
    
    
    • urls.py配置
    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请求,响应内容')
    

    局部使用解析器

    仅处理请求头content-type为application/json的请求体

    from rest_framework.parsers import JSONParser  # json格式
    from rest_framework.parsers import FormParser
    from rest_framework.parsers import MultiPartParser
    
    
    # JSONParser: json数据
    # FormParser: urlencoded
    # MultiPartParser:form-data
    class Book(APIView):
        parser_classes = [JSONParser,]
    
        def get(self, request, *args, **kwargs):
            return Response('get ok')
    
        def post(self, request, *args, **kwargs):
            print(request._request.GET)
            print(request.data)
            print(request.data.dict())
            # print(request.data.dict())
            return Response({
                'status': 0,
                'msg': "post ok"
            })
    

    仅处理请求头content-type为application/x-www-form-urlencoded 的请求体

     parser_classes = [FormParser]
    

    仅处理请求头content-type为multipart/form-data的请求体

    parser_classes = [MultiPartParser,]
    
    

    仅上传文件

    from django.conf.urls import url, include
    from web.views import TestView
    
    urlpatterns = [
        url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'),
    ]
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    from rest_framework.parsers import FileUploadParser
    
    
    class TestView(APIView):
        parser_classes = [FileUploadParser, ]
    
        def post(self, request, filename, *args, **kwargs):
            print(filename)
            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请求,响应内容')
    <!DOCTYPE html>
    <html lang="en">
    <head>
        
        <title>Title</title>
    </head>
    <body>
    <form action="http://127.0.0.1:8000/test/f1.numbers" method="post" enctype="multipart/form-data">
        <input type="text" name="user" />
        <input type="file" name="img">
    
        <input type="submit" value="提交">
    
    </form>
    </body>
    </html>
    

    同时多个Parser

    当同时使用多个parser时,rest framework会根据请求头content-type自动进行比对,并使用对应parser

    from django.conf.urls import url, include
    from web.views import TestView
    
    urlpatterns = [
        url(r'test/', TestView.as_view(), name='test'),
    ]
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
    
    
    class TestView(APIView):
        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请求,响应内容')
    

    源码分析

    解析模块源码分析
    1、APIView的dispatch方法:self.initialize_request(request, *args, **kwargs)内部还提供了数据解析
    2、self.get_parser_context(request)提供要解析的数据,self.get_parsers()提供解析的类对象(内部从配置中找解析类)

    入口:dispatch()方法

    request = self.initialize_request(request, *args, **kwargs)
    
    
        def initialize_request(self, request, *args, **kwargs):
            """
            Returns the initial request object.
            """
            # 准备要解析的内容
    
            parser_context = self.get_parser_context(request)
    
            return Request(
                request,
                # 解析模块,在封装原生的request的时候,将数据一并解析
    
                parsers=self.get_parsers(),#获取解析类
                authenticators=self.get_authenticators(),# 处理请求
                negotiator=self.get_content_negotiator(),# 处理导航的
                parser_context=parser_context
            )
    

    解析的内容

        def get_parser_context(self, http_request):
            """
            Returns a dict that is passed through to Parser.parse(),
            as the `parser_context` keyword argument.
            """
            # Note: Additionally `request` and `encoding` will also be added
            #       to the context by the Request object.
    
            # 压迫被解析的内容
            return {
                'view': self,
                'args': getattr(self, 'args', ()),
                'kwargs': getattr(self, 'kwargs', {})
            }
    
        def get_parsers(self):
            """
            Instantiates and returns the list of parsers that this view can use.
            """
            # 能够完成局部和全局的 配置
            return [parser() for parser in self.parser_classes]
    
    
    # 1 在调用request.data时,才进行解析,由此入手
        @property
        def data(self):
            if not _hasattr(self, '_full_data'):
                self._load_data_and_files()
            return self._full_data
            
    # 2 查看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)
    
    # 3 查看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
        
    # 4 最终调用parser的解析方法来解析parsed = parser.parse(stream, media_type, self.parser_context)
    # 1 Request实例化,parsers=self.get_parsers()
        Request(
                    request,
                    parsers=self.get_parsers(),
                    authenticators=self.get_authenticators(),
                    negotiator=self.get_content_negotiator(),
                    parser_context=parser_context
                )
    # 2 get_parsers方法,循环实例化出self.parser_classes中类对象
        def get_parsers(self):
            return [parser() for parser in self.parser_classes]            
    
    # 3 self.parser_classes 先从类本身找,找不到去父类找即APIVIew 中的
        parser_classes = api_settings.DEFAULT_PARSER_CLASSES
    # 4 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
     # 5 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
    
  • 相关阅读:
    leetcode回溯总结
    排序算法详解
    Java核心基础知识泛型
    leetcode贪心算法
    Linux虚拟机配置及安装Redis
    HJ6质数因子
    冒泡排序(升序)
    动态规划 背包问题
    配置mycatschema.xml
    HJ106字符逆序
  • 原文地址:https://www.cnblogs.com/SkyOceanchen/p/11895474.html
Copyright © 2020-2023  润新知