drf之請求與響應 Request from rest_framework.request import Request def __init__(self, request, parsers=None, authenticators=None, negotiator=None, parser_co ...
drf之請求與響應
Request
from rest_framework.request import Request
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
# 二次封裝request,將原生request作為drf request對象的 _request 屬性
self._request = request
def __getattr__(self,item):
return getattr(self._request,item)
REST framework 傳入視圖的request對象不再是Django預設的HttpRequest對象,而是REST framework提供的擴展了HttpRequest類的Request類的對象。
REST framework 提供了Parser解析器,在接收到請求後會自動根據Content-Type指明的請求數據類型(如JSON、表單等)將請求數據進行parse解析,解析為類字典[QueryDict]對象保存到Request對象中。
Request對象的數據是自動根據前端發送數據的格式進行解析之後的結果。
無論前端發送的哪種格式的數據,我們都可以以統一的方式讀取數據。
Request類:屬性或方法
# 請求對象.data:前端以三種編碼方式傳入的數據,都可以取出來
# 請求對象.query_params 與Django標準的request.GET相同,只是更換了更正確的名稱而已。
Response
from rest_framework.response import Response
REST framework提供了一個響應類Response,使用該類構造響應對象時,響應的具體數據內容會被轉換(render渲染)成符合前端需求的類型。
REST framework提供了Renderer 渲染器,用來根據請求頭中的Accept(接收數據類型聲明)來自動轉換響應數據到對應格式。如果前端請求中未進行Accept聲明,則會採用預設方式處理響應數據,我們可以通過配置來修改預設響應格式。
Response類:屬性或方法
def __init__(self, data=None, status=None,
template_name=None, headers=None,
exception=False, content_type=None):
#data:你要返回的數據,字典
#status:返回的狀態碼,預設是200,
-from rest_framework import status在這個路徑下,它把所有使用到的狀態碼都定義成了常量
#template_name 渲染的模板名字(自定製模板),不需要瞭解
#headers:響應頭,可以往響應頭放東西,就是一個字典
#content_type:響應的編碼格式,application/json和text/html;
drf能夠解析的請求編碼,響應編碼
響應狀態碼
# 正常返回信息1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
# 返回成功2xx
HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS
# 重定向3xx
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT
# 客戶端錯誤4xx
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
# 客戶端錯誤5xx
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
請求編碼
能夠解析的請求編碼
預設能夠解析:urlencoded、form-data、json
其實通過配置完成:項目沒有配置,是在drf內置的配置文件中提前好了
drf也是有倆套的:
一套是項目中得配置(settings.py),一套是預設的配置
drf的配置文件settings.py中有DEFAULT_PARSER_CLASSES(預設的解析類)
-'rest_framework.parsers.JSONParser', 可以解析json格式
-'rest_framework.parsers.FormParser', 可以解析urlencoded格式
-'rest_framework.parsers.MultiPartParser' 可以解析form-data格式
想讓我們的介面只能接受json格式
方式一:全局配置---》項目配置文件---》以後所有的介面都遵循這個配置
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
# 'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser',
],
}
方式二:局部配置
class TestView(APIView):
parser_classes = [JSONParser,FormParser,MultiPartParser]
總結
解析類的使用順序:優先用視圖類自己的,然後用項目配置文件,最後用內置的
實際項目如何配置:
-基本上都運行JSONParser,FormParser
-如果上傳文件只允許MultiPartParser
drf之視圖組件
由於drf提供了一個頂層的視圖類APIView,我們可以通過繼承APIView寫視圖類
但是後期我們可能需要序列化的表比較多,這可能就需要我們重覆的書寫視圖函數的五個介面,這時候我們就可以使用面向對象的繼承,封裝,使用GenericAPIView進行書寫視圖函數的5個介面
2個視圖基類
# APIView
# GenericAPIView-->繼承了APIView
-類屬性:
queryset = User.objects.all()
serializer_class = UserSerializer
-方法:
self.get_object() # 根據pk獲取單個數據
self.get_serializer # 獲取要使用的序列化類
self.get_queryset() # 獲取所有要序列化數據
原來我們基於apiview寫的5個介面是這樣的:
class UserView(APIView):
def get(self, request):
book_list = User.objects.all()
ser = UserSerializer(instance=book_list, many=True)
return Response(ser.data)
def post(self, request):
ser = UserSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': "新增成功"}, status=201)
else:
return Response({'code': 101, 'msg': ser.errors})
class UserDetailView(APIView):
def get(self, request, pk):
book = User.objects.filter(pk=pk).first()
ser = UserSerializer(instance=book)
return Response(ser.data)
def put(self, request, pk):
book = User.objects.filter(pk=pk).first()
ser = UserSerializer(instance=book, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': "修改成功"}, status=201)
else:
return Response({'code': 101, 'msg': ser.errors})
def delete(self, request, pk):
User.objects.filter(pk=pk).delete()
return Response('{'code': 100, 'msg': '刪除成功'}')
現在我們基於GenericAPIView寫5個介面:
queryset = User.objects.all()
serializer_class = UserSerializer
對於不同的模型表,開設的介面我們只需要該上面兩行代碼就行
from rest_framework.generics import GenericAPIView
class UserView(GenericAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def get(self, request):
book_list = self.get_queryset()
ser = self.get_serializer(instance=book_list, many=True)
return Response(ser.data)
def post(self, request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': "新增成功"}, status=201)
else:
return Response({'code': 101, 'msg': ser.errors})
class UserDetailView(GenericAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def get(self, request, pk):
book = self.get_object()
ser = self.get_serializer(instance=book)
return Response(ser.data)
def put(self, request, pk):
book = self.get_object()
ser = self.get_serializer(instance=book, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': "修改成功"}, status=201)
else:
return Response({'code': 101, 'msg': ser.errors})
def delete(self, request, pk):
self.get_queryset().filter(pk=pk).delete()
return Response('{'code': 100, 'msg': '刪除成功'}')
進一步優化:基於GenericAPIView和5個視圖擴展類寫的介面
from rest_framework.mixins import ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin
# views.py
class Book3View(GenericAPIView,ListModelMixin,CreateModelMixin):
queryset=Book.objects
serializer_class = BookSerializer
def get(self,request):
return self.list(request)
def post(self,request):
return self.create(request)
class Book3DetailView(GenericAPIView,RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin):
queryset = Book.objects
serializer_class = BookSerializer
def get(self, request,pk):
return self.retrieve(request,pk)
def put(self, request,pk):
return self.update(request,pk)
def delete(self,request,pk):
return self.destroy(request,pk)
# urls.py
# 使用GenericAPIView+5 個視圖擴展類 重寫的
path('books3/', views.Book3View.as_view()),
re_path('books3/(?P<pk>\d+)', views.Book3DetailView.as_view()),
再進一步優化:使用ModelViewSet編寫5個介面
# views.py
from rest_framework.viewsets import ModelViewSet
class Book5View(ModelViewSet): #5個介面都有,但是路由有點問題
queryset = Book.objects
serializer_class = BookSerializer
# urls.py
# 使用ModelViewSet編寫5個介面
path('books5/', views.Book5View.as_view(actions={'get':'list','post':'create'})), #當路徑匹配,又是get請求,會執行Book5View的list方法
re_path('books5/(?P<pk>\d+)', views.Book5View.as_view(actions={'get':'retrieve','put':'update','delete':'destroy'})),