解析模块
解析模块
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