上一篇分析了请求模块的源码,如下:
def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) return Request( request, parsers=self.get_parsers(), authenticators=self.get_authenticators(), negotiator=self.get_content_negotiator(), parser_context=parser_context )
上述源码中parsers=self.get_parsers()就是解析模块源码的入口
我们点击get_parsers进入查看该方法
def get_parsers(self): """ Instantiates and returns the list of parsers that this view can use. """ return [parser() for parser in self.parser_classes]
该方法实例化并返回此视图可以使用的解析器列表,我们点击parser_classes,查看解析器列表
api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) parser_classes = api_settings.DEFAULT_PARSER_CLASSES
我们会发现解析器列表,是从api_settings中的DEFAULT_PARSER_CLASSES查找的,而api_settings又等于APISettings中的DEFAULTS,我们可以从settings中的DEFAUITS列表的DEFAULT_PARSER_CLASSES,如下:
DEFAULTS = { # Base API policies 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ], 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ], }
我们可以看到,drf默认的解析器列表中有3个解析器,这3个解析器中都有media_type属性,代表支持解析的数据提交类型
- JSONParser:media_type = 'application/json'
- FormParser:media_type = 'application/x-www-form-urlencoded'
- MultiPartParser: media_type = 'multipart/form-data'
如果我们想在以上3个解析器的基础上,再加上文件类型的解析器,那么需要全局配置。
我们可以在settings.py文件中设置REST_FRAMEWORK配置,具体设置如下:
REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser', 'rest_framework.parsers.FileUploadParser' ], }
这样,我们以后所有继承于APIView的类视图都可以解析上面配置的4种数据类型,但是如果我们想某个视图只能解析json格式的数据,那么就需要局部配置
默认全局配置是因为我们写的视图继承自APIView,APIView中配置了类属性parser_classes,所以我们自己编写的视图函数中,也设置个类属性,并且导入JSONParser解析器
from rest_framework.parsers import JSONParser class TestView(APIView): # 局部解析类配置 parser_classes = [JSONParser] def post(self, request, *args, **kwargs): print(request.data) return Response("drf post ok")
接着我们使用application/x-www-form-urlencoded提交数据,会有如下报错
{ "detail": "不支持请求中的媒体类型 “application/x-www-form-urlencoded”。" }
然后我们使用multipart/form-data提交数据,也会报错
{ "detail": "不支持请求中的媒体类型 “multipart/form-data; boundary=--------------------------022567055086460827891894”。" }
最后我们使用application/json提交数据,响应成功
"drf post ok"
自定义解析器
如果我们想自定义一个解析器,也很简单,默认的3个解析器都继承自BaseParser,我们查看下源码
class BaseParser: """ All parsers should extend `BaseParser`, specifying a `media_type` attribute, and overriding the `.parse()` method. """ media_type = None def parse(self, stream, media_type=None, parser_context=None): """ Given a stream to read from, return the parsed representation. Should return parsed data, or a `DataAndFiles` object consisting of the parsed data and files. """ raise NotImplementedError(".parse() must be overridden.")
如果我们需要自定义解析器,那么就必须继承自BaseParser,并且设置属性media_type,还要重写parse方法,有需求的小伙伴可以自行尝试,这里就不演示了