一、示例
1、api/urls.py
from django.urls import path, re_path
from api.views import UserView, ParserView
urlpatterns = [
# path('users/', UserView.as_view()),
re_path('(?P<version>[v1|v2]+)/users/', UserView.as_view(), name='api_user'),
path('parser/', ParserView.as_view(), name='api_parer'), # 添加这句
]
2、api/views.py
JSONParser
:只能解析content-type:application/json
的头FormParser
:只能解析content-type:application/x-www-form-urlencoded
的头
from rest_framework.parsers import JSONParser, FormParser
class ParserView(APIView):
parser_classes = [JSONParser, FormParser]
def post(self, request, *args, **kwargs):
print(request.data)
return HttpResponse('解析')
3、使用 postman 发送 json 数据测试后台是否能解析:
(1)、设置为 post 方式,headers 中添加数据类型为 json
(2)、body 中选择 raw,然后选择 json 类型,最后就是在空白处构建要发送的 json 数据(记得是双引号):
后台结果:
如果是 content-type:application/x-www-form-urlencoded
类型数据,不需要设置请求头,默认就是。但是 body
中需要设置为 x-www-form-urlencoded
。
二、源码分析
1、dispatch()
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
# 对原生的 request 对象进行加工,丰富了
# request= Request(request,parsers=self.get_parsers(),authenticators=self.get_authenticators(),negotiator=self.get_content_negotiator(),parser_context=parser_context)
# 第一个参数为原生的 request 对象,封装原生 request
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
2、initialize_request()
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object. 封装原生 request 对象
"""
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
)
3、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]
4、parser_classes
class APIView(View):
# The following policies may be set at either globally, or per-view.
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
# 从 settings 中获取解析器
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
# Allow dependency injection of other settings to make testing easier.
settings = api_settings
5、全局配置解析器 settings
:
REST_FRAMEWORK = {
# 解析器
"DEFAULT_PARSER_CLASSES":["rest_framework.parsers.JSONParser","rest_framework.parsers.FormParser"]
}
源码流程图
根据请求头 content-type
选择对应的解析器就请求体内容进行处理。
三、仅处理请求头 content-type 为 application/json 的请求体
1、urls.py
from django.urls import path, re_path, include
from api.views import TestView2
urlpatterns = [
re_path(r'(?P<version>[v1|v2]+)/test2', TestView2.as_view()),
]
2、views.py
rom rest_framework.views import APIView
from rest_framework.parsers import JSONParser, FormParser
from rest_framework.response import Response
class TestView2(APIView):
parser_classes = [JSONParser]
def post(self, request, *args, **kwargs):
print(request.content_type) # application/json
# 获取请求值,并发 JSONParser 处理
print(request.data) # {'name': 'rose', 'age': 18}
# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
print(request.POST) # <QueryDict: {}>
print(request.FILES) # <MultiValueDict: {}>
return Response('响应内容')
四、仅处理请求头 content-type 为 application/x-www-form-urlencoded 的请求体
1、urls.py
from django.urls import path, re_path, include
from api.views import TestView2
urlpatterns = [
re_path(r'(?P<version>[v1|v2]+)/test2', TestView2.as_view()),
]
2、views.py
rom rest_framework.views import APIView
from rest_framework.parsers import JSONParser, FormParser
from rest_framework.response import Response
class TestView2(APIView):
parser_classes = [FormParser]
def post(self, request, *args, **kwargs):
print(request.content_type) # application/x-www-form-urlencoded
# 获取请求值,并发 JSONParser 处理
print(request.data) # <QueryDict: {'123': ['']}>
# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
print(request.POST) # <QueryDict: {'123': ['']}>
print(request.FILES) # <MultiValueDict: {}>
return Response('响应内容')
五、仅处理请求头content-type为multipart/form-data的请求体
1、urls.py
from django.urls import path, re_path, include
from api.views import TestView2
urlpatterns = [
re_path(r'(?P<version>[v1|v2]+)/test2', TestView2.as_view()),
]
2、views.py
rom rest_framework.views import APIView
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
from rest_framework.response import Response
class TestView2(APIView):
parser_classes = [MultiPartParser]
def post(self, request, *args, **kwargs):
print(request.content_type) # multipart/form-data
# 获取请求值,并发 JSONParser 处理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response('响应内容')
3、upload.html
<!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>
六、仅上传文件
1、urls.py
from django.urls import path, re_path, include
from api.views import TestView2
urlpatterns = [
re_path(r'(?P<version>[v1|v2]+)/test2', TestView2.as_view()),
]
2、views.py
rom rest_framework.views import APIView
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser, FileUploadParser
from rest_framework.response import Response
class TestView2(APIView):
parser_classes = [FileUploadParser]
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('响应内容')
3、upload.html
<!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>
七、其他
多个 parser
当同时使用多个 parser
时,rest framework
会根据请求头 content-type
自动进行比对,并使用对应 parser
#!/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请求,响应内容')
全局使用
settings.py
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES':[
'rest_framework.parsers.JSONParser'
'rest_framework.parsers.FormParser'
'rest_framework.parsers.MultiPartParser'
]
}
Tips: 个别特殊的值可以通过Django的request对象 request._request 来进行获取
总结
JSONParser
,解析数据类型:content-type:application/json
FormParser
,解析数据类型:content-type:application/x-www-form-urlencoded
- 支持全局配置解析器类型