REST-Framework: 解析器

Rest-Framework中的解析器和响应器是对应的,分别对客户端的请求和服务器的响应相对应做处理

一 解析器的作用

根据请求头 content-type 选择对应的解析器对请求体内容进行处理。

有application/json,x-www-form-urlencoded,form-data等格式, 可以自己自行配置支持或者不支持哪种格式, 一般在实际的生产环境中用json一种数据格式进行数据交互就够了, 如果需要form-data来进行文件处理,再将该格式加入到解析器中即可

二 全局使用解析器

setting里

 
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请求,响应内容')

 

三 局部使用解析器

a. 仅处理请求头content-type为application/json的请求体

 
from django.conf.urls import url, include
 
from web.views.s5_parser 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
 
 
 
 
 
class TestView(APIView):
 
parser_classes = [JSONParser, ]
 
 
 
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请求,响应内容')

 

b. 仅处理请求头content-type为application/x-www-form-urlencoded 的请求体

 
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 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的请求体

 
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 MultiPartParser
 
 
 
 
 
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请求,响应内容')

 

 

 
<!DOCTYPE html>
 
<html lang="en">
 
<head>
 
<meta charset="UTF-8">
 
<title>Title</title>
 
</head>
 
<body>
 
<form action="http://127.0.0.1:8000/test/" method="post" enctype="multipart/form-data">
 
<input type="text" name="user" />
 
<input type="file" name="img">
 
 
 
<input type="submit" value="提交">
 
 
 
</form>
 
</body>
 
</html>

 

d. 仅上传文件

 
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>
 
<meta charset="UTF-8">
 
<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>

 

e. 同时多个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 在调用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
 

 

posted @ 2020-11-13 00:08  Οo白麒麟оΟ  阅读(120)  评论(0编辑  收藏  举报