DRF--解析器Parsers

前戏

解析器是干什么的?因为前后端分离,因为可能采用json、xml、html等各种不同格式的内容,后端必须要有一个解析器来解析前端发送过来的数据,也就是翻译器!否则后端凭什么看懂前端的数据?对应地,后端也有一个渲染器Render,和解析器是相反的方向,将后端的数据翻译成前端能明白的数据格式。

DRF框架提供了许多内置的Parser类,用来处理各种媒体类型的请求,比如json,比如xml。还支持自定义解析器,可以灵活地设计API接受的媒体类型。

Django原生的解析器对于post的数据,如果要从request.body中解析出来放到request.POST中,那么必须同时满足两个条件:

  • 请求头部 Content_type = 'application/x-www-form-urlencoded'
  • 数据格式必须是: name=xxx&password=xxx&email=xxx.....

而对于前端发送过来的例如JSON格式的数据则无法处理(当然你自己处理也是可以的)。DRF则不同,它提供了一些额外的解析器帮我们处理各种格式。

DRF的parsers模块非常简单,只定义了几个解析器类:

  • BaseParser:解析器基类,以下四个类都直接继承它
  • JSONParser
  • FormParser
  • MultiPartParser
  • FileUploadParser

JSONParser

解析 JSON 格式的请求内容。其.media_type属性值为  application/json

FormParser

解析HTML表单内容,使用QueryDict的数据填充request.data。这也是Django原生支持的解析方式。

通常我们希望同时支持FormParser和MultiPartParser两种解析器,以便完全支持HTML表单数据。

.media_type:  application/x-www-form-urlencoded

MultiPartParser

解析多部分的HTML表单内容,支持文件上传。

.media_type:  multipart/form-data

FileUploadParser

解析原始文件上传内容。此时, request.data 属性将是一个字典,并且只包含一个键,这个键叫做 'file' ,对应的值包含上传的文件内容。

如果使用FileUploadParser解析器的视图,在被调用的时候URL中携带一个 filename 关键字参数,则该参数将被用作文件名。如果在没有这个关键字参数的情况下调用它,则客户端必须在HTTP头部的 Content-Disposition 中设置文件名。

DRF在运行的时候如何知道该使用哪个解析器呢?

DRF将有效的解析器集定义为类的列表。当  request.data 被访问时,REST框架将检查请求头部的 Content-Type 属性,以此来确定要使用哪个解析器来解析数据。所以,要注意!解析器只有在请求request.data的时候才会被调用!如果不需要data数据,那么就不用解析。

注意:在开发客户端应用程序时,务必确保在请求头部中包含 Content-Type 属性。如果未设置内容类型,则大多数客户端将默认使用 'application/x-www-form-urlencoded' 类型

解析器的相关配置参数

可以在Django项目的settings.py文件中,使用 DEFAULT_PARSER_CLASSES 配置项,进行全局的解析器设置。例如,以下设置仅允许解析JSON格式的请求,而不是默认的JSON或表单数据:

REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',
    )
}

当然,也可以同时支持多种解析器,比如下面的配置,这也是DRF默认的解析器配置:

REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser',
    )
}

几种解析器的写法没有先后顺序的要求,不像中间件那样的配置有顺序关系。

DRF支持视图级别的解析器,比如为基于APIView的类视图专门指定使用的解析器,核心是指定parser_classes 属性为某个解析器:

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


class ExampleView(APIView):

    # 配置解析器
    parser_classes = (JSONParser,)
    def post(self, request):
        return Response("Hello World")

当然,也可以为使用  @api_view 装饰器改造的视图指定专用的解析器,核心是@parser_classes((JSONParser,)) 装饰器:

from rest_framework.decorators import api_view
from rest_framework.decorators import parser_classes
from rest_framework.parsers import JSONParser
from rest_framework.response import Response


@api_view(['POST'])
@parser_classes((JSONParser,))  # 配置解析器
def example_view(request):
    return Response({'received data': request.data})

如果全局配置了解析器,视图里也配置了,则视图里的解析器具有更高的优先级。

自定义解析器

要自定义解析器,必须继承 BaseParser 类,设置 .media_type 属性,并实现 .parse(self, stream, media_type, parser_context) 方法,该方法应返回将用于填充 request.data 属性的数据。

parse()方法的参数说明:

stream:类似于流的对象,表示请求的主体。

media_type:请求内容的媒体类型,可选。根据请求头部的 Content-Type: ,这可能比渲染器的 media_type 属性更具体,并且可能包括媒体类型参数。例如 "text/plain; charset=utf-8" 。

parser_context:可选,字典格式。如果提供,将包含解析请求内容可能需要的任何其他上下文。可选,字典格式。如果提供,将包含解析请求内容可能需要的任何其他上下文。

下面自定义了一个纯文本解析器,它将字符串形式表示的请求内容,填充到request.data属性。

from rest_framework.parsers import BaseParser


class PlainTextParser(BaseParser):
    """
  纯文本解析器
 """
    media_type = 'text/plain'
    def parse(self, stream, media_type=None, parser_context=None):
        """ 简单的返回一个请求主体内容的字符串形式 """
        return stream.read()

YAML解析器

djangorestframework-yaml 包为我们提供了解析和渲染yaml格式的能力。它以前直接包含在REST框架包中,现在作为第三方包出现。

直接用pip安装

pip install djangorestframework-yaml 

可以进行下面的配置:

REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework_yaml.parsers.YAMLParser',
         ),
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework_yaml.renderers.YAMLRenderer',
        ),
}

XML解析器

pip install djangorestframework-xml 

配置

REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework_xml.parsers.XMLParser',
    ),
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework_xml.renderers.XMLRenderer',
    ),
}
posted @ 2020-10-25 22:34  邹邹很busy。  阅读(467)  评论(0编辑  收藏  举报