1. Django中數據的解析
Django接收請求和請求相關的數據時對請求頭和數據格式有一定的要求,首先看下對請求頭要求。只有請求頭中有 application/x-www-form-urlencoded
,request.POST中才可能有值(去request.body中解析數據):
urls.py:
from django.urls import path, re_path
from . import views
urlpatterns = [
re_path('(?P<version>[v1,v2]+)/django_request/', views.DjangoRequest.as_view()),
]
views.py:
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
class DjangoRequest(APIView):
def post(self, request, *args, **kwargs):
from django.core.handlers.wsgi import WSGIRequest
print(type(request._request)) # <class 'django.core.handlers.wsgi.WSGIRequest'>
return HttpResponse()
可以看下源碼中是如何做的:
上面說過即便帶着這個Content-Type也不一定有值,數據解析(轉換)時對數據格式也是有要求的,數據格式需要是 ?name=thanlon&age=23
這種格式。
之後遇到request.POST沒有值,可以考慮這兩個因素。
Form表單提交默認的Content-Type就是application/x-www-form-urlencoded,數據格式也是?name=thanlon&age=23。如果是Ajax提交:
$.ajax({
url:...,
type:POST,
data:{'name':'thanlon','age':23}, // 內部也會轉換成?name=thanlon&age=23,再帶上Content-Type:application/x-www-form-urlencoded提交過去
})
Ajax可以定製請求頭,這種情況下request.body中有值,但是request.post中沒有值:
$.ajax({
url:...,
headers:{'Content-Type':'application/json'},
type:POST,
data:{'name':'thanlon','age':23},
})
Ajax將數據轉換爲JSON字符串傳到後臺,這種情況下request.body中有值,但是request.post中還是沒有值:
$.ajax({
url:...,
headers:{'Content-Type':'application/json'},
type:post,
data:JSON.stringfy({'name':'thanlon','age':23}), // {'name':'thanlon','age':23}
})
這種情況下request.body中是有值,可以使用 json.loads(request.body)
拿到json數據。當然,需要先把字節類型轉換爲字符串類型。
2. 內置解析類的使用
常用的內置解析類有 JSONParser和FormParser
,JSONParser類可以解析請求頭中Content-Type是application/json的頭的數據,FormParser類可以解析請求中Content-Type是application/x-www-form-urlencoded的頭的數據。Content-Type是application/json時:
urls.py:
from django.urls import re_path
from . import views
urlpatterns = [
re_path('(?P<version>[v1,v2]+)/parser/', views.ParserView.as_view()),
]
views.py:
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from rest_framework.parsers import JSONParser
class ParserView(APIView):
parser_classes = [JSONParser, ]
def post(self, request, *args, **kwargs):
"""
允許用戶發送JSON格式數據,請求頭中Content-Type是application/json,數據是{'name': 'erics'}
:param request:
:param args:
:param kwargs:
:return:
"""
# request.data會觸發解析類進行數據的解析
data = request.data
print(type(data), data) # <class 'dict'> {'name': 'erics'}
return HttpResponse(f'{data}')
Content-Type是application/x-www-form-urlencoded時:
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from rest_framework.parsers import JSONParser, FormParser
class ParserView(APIView):
parser_classes = [JSONParser, FormParser,]
def post(self, request, *args, **kwargs):
data = request.data
"""
1、獲取用戶請求
2、獲取用戶請求體
3、獲取用戶請求頭,需要與parser_classes = [JSONParser, FormParser]中支持的請求頭進行比較
4、JSONParser、FormParser對象解析請求體
5、解析的結果放到request.data中
"""
print(type(data), data) # <class 'django.http.request.QueryDict'> <QueryDict: {'name': ['erics']}>
return HttpResponse(f'{data}')
Content-Type是multipart/form-data時,需要用到MultiPartParser解析類:
如果都不可以解析請求的數據:
配置多個請求類時,請求頭中的Content-Type與哪一個解析類匹配就使用哪個解析。
全局配置只需要在配置文件中添加解析類的路徑即可:
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES':
[
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser',
]
}
3. 內置解析類
Django REST framework內置的解析類實際上有4種,都是根據請求頭中Content-Type值的不同來對數據做不同的解析:
4. 解析源碼流程