django中的请求解析
满足下面两个要求,request.body的值才会解析到request.POST中
1、请求头中:Content-Type:application/x-www-form-urlencoded
2、请求体中:a=1&b=2&c=3这样的格式
form表达和ajax默认是满足上面的要求,所以可以在request.POST中取到值
如果请求头是application/json,需要自己去request.body中取值解析,不会自动解析到request.POST中
解析器模块
解析器的作用就是对请求体进行解析
rest_framework.parsers
是restframework提供的解析器模块,其他权限类都要继承BaseParser
类
parsers属性定义
在dispatch()
方法中,有下面两段关键代码:
...
#封装Request对象
request = self.initialize_request(request, *args, **kwargs)
...
#认证、权限、限流验证
self.initial(request, *args, **kwargs)
...
在initialize_request()
方法中封装了新的Request对象
class APIView(View):
...
parser_classes = api_settings.DEFAULT_PARSER_CLASSES#django settings.py中定义DEFAULT_PARSER_CLASSES会覆盖restframework settings.py中的定义
...
def get_parsers(self):
"""
Instantiates and returns the list of parsers that this view can use.
"""
return [parser() for parser in self.parser_classes]
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.parser_classes
self指向IndexView实例,先去IndexView中查找,如果未定义再去父类中查找
本例settings.py定义:
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES':['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser']
}
所以parsers=[JSONParser(),FormParser]
解析流程
只有调用request.data
才会根据请求的content_type值,匹配上面获取到的解析器对象,然后去解析请求体
#rest_framework negotiation.py中DefaultContentNegotiation类
def select_parser(self, request, parsers):
"""
Given a list of parsers and a media type, return the appropriate
parser to handle the incoming request.
"""
for parser in parsers:
if media_type_matches(parser.media_type, request.content_type):#第二个参数是request对象的content_type属性
return parser
return None
#rest_framework request.py中Request类
@property
def content_type(self):
meta = self._request.META
return meta.get('CONTENT_TYPE', meta.get('HTTP_CONTENT_TYPE', ''))
def _parse(self):
"""
Parse the request content, returning a two-tuple of (data, files)
May raise an `UnsupportedMediaType`, or `ParseError` exception.
"""
media_type = self.content_type #获取请求的content_type
...
#self.parsers=[JSONParser(),FormParser]
parser = self.negotiator.select_parser(self, self.parsers) #根据content_type值选择对应的解析器
if not parser:
raise exceptions.UnsupportedMediaType(media_type)
try:
parsed = parser.parse(stream, media_type, self.parser_context) #开始解析请求体数据
except Exception:
...
# Parser classes may return the raw data, or a
# DataAndFiles object. Unpack the result as required.
try:
return (parsed.data, parsed.files)
except AttributeError:
empty_files = MultiValueDict()
return (parsed, empty_files)
def _load_data_and_files(self):
"""
Parses the request content into `self.data`.
"""
if not _hasattr(self, '_data'):
self._data, self._files = self._parse()
...
@property
def data(self):
if not _hasattr(self, '_full_data'):
self._load_data_and_files()
return self._full_data
以JSONParser类为例,查看实现源码:
class JSONParser(BaseParser):
"""
Parses JSON-serialized data.
"""
media_type = 'application/json'
renderer_class = renderers.JSONRenderer
strict = api_settings.STRICT_JSON
def parse(self, stream, media_type=None, parser_context=None):
"""
Parses the incoming bytestream as JSON and returns the resulting data.
"""
parser_context = parser_context or {}
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
try:
decoded_stream = codecs.getreader(encoding)(stream)
parse_constant = json.strict_constant if self.strict else None
return json.load(decoded_stream, parse_constant=parse_constant)
except ValueError as exc:
raise ParseError('JSON parse error - %s' % str(exc))
用postman发送请求,请求头Content-Type:application/json
,请求体:{"name":"tom","age":12}
JSONParser
调用parse()
方法解析,json.load(decoded_stream, parse_constant=parse_constant)
将json字符串读取转换成字典
全局配置
可以在django项目的settings.py中设置REST_FRAMEWORK
变量,配置全局解析器:
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES':['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser']
}
局部配置
如果只是某个视图使用,可以在类中定义属性,比如:parser_classes = [JSONParser,FormParser]
网友评论