rest_framework:解析器
一、解析器的作用
根据请求头content-type选择对应的解析器对请求体内容进行处理。
有application/json,x-www-form-urlencoded,form-data等格式
二、局部使用解析器
a、仅处理请求头content-type为application/json的请求体
路由:
url(r'^publish/$',views.PublishView.as_view()),
视图:
# 局部使用解析器 from rest_framework.response import Response from rest_framework.request import Request from rest_framework.parsers import JSONParser class PublishView(APIView): parser_classes = [JSONParser,] # 获取所有的数据 def get(self,request): publish_list=models.Publish.objects.all() ps=PublishSerializers(publish_list,many=True) return Response(ps.data) def post(self,request,*args,**kwargs): print(request.content_type) # 获取请求的值,并使用对应的jsonparser进行处理 print(request.data) print(type(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请求,响应内容')
通过get方法可以获取数据,对数据新增的时候只有json这一种格式,使用其它方式新增数据提示失败,不支持
b,仅处理请求头content-type为application/x-www-form-urlencodede的请求体
设置url:
url(r'^publish/$',views.TestView.as_view()),
设置路由:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import FormParser
class TestView(APIView): parser_classes = [FormParser,] 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请求,响应内容')
c,仅处理请求头content-type为multipart/form-data的请求体
设置url:
url(r'^publish/$',views.TestView.as_view()),
设置视图:
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request from rest_framework.parsers import FormParser from rest_framework.parsers import MultiPartParser
# 只处理请求头content-type为multipart/from-data的请求体
class TestView(APIView):
parser_classes = [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请求,响应内容')
只允许form-data格式的请求,其它格式或请求全部会拒绝:
新建一个前端页面提交新增数据输入框:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="http://127.0.0.1:8000/publish/" method="post" enctype="multipart/form-data"> <input type="text" name="user" /> <input type="text" name="city"> <input type="submit" value="提交"> </form> </body> </html>
提交数据后返回页面:
d,仅上传文件:
路由:
url(r'publish/(?P<filename>[^/]+)', views.TestView.as_view()),
视图:
# 只处理文件 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请求,响应内容')
编辑前端web页面:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="http://127.0.0.1:8000/publish/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>
前端页面展示:
文件上传成功,获取返回值:
e,同时多个Parser
同时使用多个parser时,rest framework会根据请求头content-type自动进行对比,并使用对应parser
设置路由:
url(r'publish/', views.TestView.as_view()),
视图:
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请求,响应内容')
支持:
JSONParser, FormParser, MultiPartParser提交数据
三、全局使用解析器
在settings中设置:
REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES':[ 'rest_framework.parsers.JSONParser' 'rest_framework.parsers.FormParser' 'rest_framework.parsers.MultiPartParser' ] }
路由设置:
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请求,响应内容')
四、源码分析
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