drf快速實現五個介面的方法
阿新 • • 發佈:2021-11-04
全域性規定請求格式編碼
# 全域性規定請求格式編碼,settings檔案配置 REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', # 第一種編碼 'rest_framework.parsers.FormParser', # 第二種編碼 'rest_framework.parsers.MultiPartParser' # 第三種編碼 ], } # 如果登出第一種編碼,也就相當於前端在新增或者修改的時候,提交的資料不能是json格式的編碼 # 如果登出第二種編碼,也就相當於前端在新增或者修改的時候,提交的資料不能是form-data格式的編碼 # 如果登出第三種編碼,也就相當於前端在新增或者修改的時候,提交的資料不能是url-encoded格式的編碼 # 同樣,如果只寫一種或者兩種,也就是說只接收前端傳過來的某一種或者某兩種編碼格式 # 區域性規定請求格式編碼,views檔案中的檢視類中寫 parser_classes = [FormParser] # 括號內代表的是url-encoded編碼格式 parser_classes = [JSONParser] # 括號內代表的是json編碼格式資料 parser_classes = [MultiPartParser] # 代表的是form-data編碼格式資料
規定響應格式編碼
# 全域性規定響應格式編碼,settings檔案配置 REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', # 第一種編碼格式 'rest_framework.renderers.BrowsableAPIRenderer', # 第二種 ],} # 如果登出第一種編碼,也就相當於後端提交資料(Response返回的時候)不能是json格式的資料返回,而是變成了其他格式的資料 # 如果登出第二種編碼,也就相當於後端提交資料(Response返回的時候)不能是瀏覽器格式的資料返回,而是變成了Json或者其他格式的資料 # 同理如果只寫一種,也就是指定那一種編碼格式返回到前端 renderer_classes = [JSONParser] renderer_classes = [BrowsableAPIRenderer]
編碼格式規定的優先順序是
區域性 > 全域性(django配置檔案) > drf配置檔案
Response的引數
data # 字典或者列表或者字串,可以將列表或者字典以json格式返回,字串的話返回到前端還是字串,返回到前端的資料放在了響應體中 status # 狀態碼,可以直接寫數字,也可以調drf中的配置常量,相當於填寫的數 template_name # 可以填一個html檔名字,會將該檔案返回到前端 headers # 響應頭,可以放一個字典,會以鍵值對的形式放回給前端響應頭裡面 content_type # 響應的編碼格式 exception # 響應的異常資訊
檢視類的兩個檢視基類(APIView和GenericAPIView)
# 檢視基類APIView和檢視基類GenericAPIView的匯入方式
from rest_framework.generics import GenericAPIView
from rest_framework.views import APIView
我們發現在寫不同表模型類的介面的時候,都大差不差,程式碼明顯冗餘,如何解決這種問題,需要用到檢視類的兩個檢視基類
from rest_framework.generics import GenericAPIView
GenericAPIView類有兩個重要的類屬性
queryset = None
serializer_class = None
可以將這兩個類屬性寫在views類檢視函式裡面
queryset = models.Book.objects.all() # 需要序列化的表的所有資料
serializer_class = 序列化器類 # 你要使用的序列化或者反序列化的類
1.雖然有queryset,但是我們一般用get_queryset方法,等同於queryset
def get(self, request):
book_queryset = self.queryset # 物件呼叫類的屬性
book_queryset = self.get_queryset() # 物件呼叫類的方法
book_queryset = models.Book.objects.all()
前面兩個等同於第三個,只不過前面兩個繼承的是GenericAPIView類
而第三個繼承的類是APIView
2.雖然有serializer_class類屬性,但是我們一般用get_serializer方法,等同於serializer_class
def get(self, request):
book = self.serializer_class(instance=book_queryset, many=True)
book = self.get_serializer(instance=book_queryset, many=True)
book = BookSerializers(instance=book_queryset, many=True)
前面兩個等同於第三個,只不過前面兩個繼承的是GenericAPIView類
而第三個繼承的類是APIView
3.獲取單條模型表的資料
def get(self,request,pk):
book_obj = models.Book.objects.filter(pk=pk).first()
book_obj = self.get_objects()
4.Response返回的時候
正常返回,跟APIView一樣
5.總結
首先,路由方面還是不變,分倆個路由
path('books/', views.MyBooks.as_view()),
path('books/<int:pk>/', views.MyBook.as_view())
其次views.py檔案中的兩個CBV類也不變
class MyBooks 和 class MyBook
---最後這兩個檢視類MyBooks和MyBook都繼承了GenericAPIView類
---繼承GenericAPIView類
---兩個類屬性:
queryset = None
serializer_class = None
---三個方法:
self.get_object() # 獲取models表中的單條資料
self.get_serializer(instance=None,data=None)
self.get_queryset() # 獲取要序列化的資料
五個檢視擴充套件類()
基於兩個檢視基類的進一步封裝,讓程式碼冗餘減少
繼承GenericAPIView類加五個檢視擴充套件類
五個試圖擴充套件類
from rest_framework.mixins import ListModelMixin get
from rest_framework.mixins import RetrieveModelMixin get
from rest_framework.mixins import UpdateModelMixin put
from rest_framework.mixins import DestroyModelMixin delete
from rest_framework.mixins import CreateModelMixin post
首先我們需要在views的檢視類繼承GenericAPIView+任意一個五個檢視擴充套件類
1.如果加的是ListModelMixin檢視擴充套件類,那麼就相當於get獲取所有圖書資訊
class MyBooks(GenericAPIView,ListModelMixin):
queryset = models.Book.objects.all()
serializer_class = BookSerializers
def get(self,request):
return self.list(request)
2.如果想新增一個數據,需要加CreateModelMixin檢視擴充套件類
def post(self,request):
return self.create(request)
需要注意的是它還有一個perform_create(self,serializer)方法,該方法是儲存校驗通過的資料,我們可以通過對他的重寫,從而達到當儲存多表的時候,實現實時的更新.serializer是校驗通過的資料serializer.save()
3.如果想獲取一個圖書資訊,需要用到RetrieveModelMixin試圖擴充套件類
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
4.如果想修改一個圖書資訊,需要用到UpdateModelMixin檢視擴充套件類
def put(self,request,*args,**kwargs):
return self.update(request,*args,**kwargs)
5.如果想刪除一個圖書資訊,需要用到DestroyModelMixin檢視擴充套件類
def delete(self,request,*args,**kwargs):
return self.destroy(request,*args,**kwargs)
需要注意的是它也寫了一個方法perform_destroy(self,instance)
我們可以重寫這個方法,在刪除之前做一點事情
6.總結,GenericAPIView類加五個檢視擴充套件類寫五個介面的步驟
首先,路由方面還是不變,分倆個路由
path('books/', views.MyBooks.as_view()),
path('books/<int:pk>/', views.MyBook.as_view())
其次views.py檔案中的兩個CBV類也不變
class MyBooks 和 class MyBook
# 最後是MyBooks類繼承了GenericAPIView加兩個檢視擴充套件類
# MyBook類繼承了GenericAPIView加三個檢視擴充套件類
九個檢視子類()
# 九個檢視子類的模組匯入如下
from rest_framework.generics import ListAPIView
from rest_framework.generics import CreateAPIView
from rest_framework.generics import ListCreateAPIView
from rest_framework.generics import RetrieveAPIView
from rest_framework.generics import UpdateAPIView
from rest_framework.generics import DestroyAPIView
from rest_framework.generics import RetrieveUpdateAPIView
from rest_framework.generics import RetrieveDestroyAPIView
from rest_framework.generics import RetrieveUpdateDestroyAPIView
1.檢視子類ListAPIView # 等同於寫了一個獲取所有圖書的get請求方式的介面
檢視子類ListAPIView = 檢視基類GenericAPIView + 檢視擴充套件類ListModelMixin
class ListAPIView(mixins.ListModelMixin,
GenericAPIView):
ListAPIView檢視子類繼承了ListModelMixin檢視擴充套件類和GenericAPIView檢視基類
2.檢視子類CreateAPIView # 等同於寫了一個新增一個圖書的post請求方式的介面
檢視子類CreateAPIView = 檢視基類GenericAPIView + 檢視擴充套件類CreateModelMixin
class CreateAPIView(mixins.CreateModelMixin,
GenericAPIView):
3.檢視子類RetrieveAPIView # 等同於寫了一個查詢一本圖書的get請求方式的介面
檢視子類RetrieveAPIView = 檢視基類GenericAPIView + 檢視擴充套件類RetrieveModelMixin
class RetrieveAPIView(mixins.RetrieveModelMixin,
GenericAPIView):
4.檢視子類UpdateAPIView # 等同於寫了一個修改一本圖書的put請求方式的介面
檢視子類UpdateAPIView = 檢視基類GenericAPIView + 檢視擴充套件類UpdateModelMixin
class UpdateAPIView(mixins.UpdateModelMixin,
GenericAPIView):
5.檢視子類DestroyAPIView # 等同於寫了一個刪除一本圖書的delete請求方式的介面
檢視子類DestroyAPIView = 檢視基類GenericAPIView + 檢視擴充套件類DestroyModelMixin
class DestroyAPIView(mixins.DestroyModelMixin,
GenericAPIView):
6.檢視子類ListCreateAPIView # 等同於寫了一個獲取所有圖書和新增一本圖書的get和post請求方式的兩個介面
檢視子類ListCreateAPIView = 檢視基類GenericAPIView + 檢視擴充套件類ListModelMixin + 檢視擴充套件類CreateModelMixin
class ListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin,
GenericAPIView):
7.檢視子類RetrieveUpdateAPIView # 等同於寫了一個獲取一本圖書和修改一本圖書的get和put請求方式的兩個介面
檢視子類RetrieveUpdateAPIView = 檢視基類GenericAPIView + 檢視擴充套件類RetrieveModelMixin + 檢視擴充套件類UpdateModelMixin
class RetrieveUpdateAPIView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
GenericAPIView):
8.檢視子類RetrieveDestroyAPIView # 等同於寫了一個獲取一本圖書和刪除一本圖書的get和delete請求方式的兩個介面
檢視子類RetrieveDestroyAPIView = 檢視基類GenericAPIView + 檢視擴充套件類
RetrieveModelMixin + 檢視擴充套件類DestroyModelMixin
class RetrieveDestroyAPIView(mixins.RetrieveModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
9.檢視子類RetrieveUpdateDestroyAPIView # 等同於寫了一個獲取一本圖書和修改一本圖書以及刪除一本圖書的get和put和delete請求方式的三個介面
檢視子類RetrieveUpdateDestroyAPIView = 檢視基類GenericAPIView + 檢視擴充套件類RetrieveModelMixin + 檢視擴充套件類UpdateModelMixin + 檢視擴充套件類DestroyModelMixin
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
10.總結
首先,路由方面還是不變,分倆個路由
path('books/', views.MyBooks.as_view()),
path('books/<int:pk>/', views.MyBook.as_view())
其次views.py檔案中的兩個CBV類也不變
class MyBooks 和 class MyBook
--只需要繼承你想要實現的介面類
--隨機組合,只要滿足五個介面就可以
檢視集
# 四個檢視集,需要匯入檢視集模組
from rest_framework.viewsets import ModelViewSet
from rest_framework.viewsets import ReadOnlyModelViewSet
from rest_framework.viewsets import ViewSet
from rest_framework.viewsets import GenericViewSet
1.檢視集ModelViewSet # 等同於寫了獲取所有,獲取單個,新增一個,修改一個,刪除一個的get,get,post,put,delete五個請求方式的介面
檢視集ModelViewSet = 檢視基類的子類GenericViewSet + ListModelMixin檢視擴充套件類
+ 檢視擴充套件類CreateModelMixin + 檢視擴充套件類RetrieveModelMixin
+ 檢視擴充套件類UpdateModelMixin + 檢視擴充套件類DestroyModelMixin
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
2.檢視集ReadOnlyModelViewSet
class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
mixins.ListModelMixin,
GenericViewSet):
pass
3.檢視集ViewSet # 等同於APIView + ViewSetMixin
class ViewSet(ViewSetMixin, views.APIView):
pass
4.GenericViewSet # 等同於GenericAPIView + ViewSetMixin
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
pass
5.檢視集的父類GenericViewSet
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
6.檢視集ModelViewSet的父類GenericViewSet的父類ViewSetMixin
所以說我們在as_view方法裡面填字典能夠對映,是該類實現的
路由匹配成功執行-->as_view方法,該方法是ViewSetMixin的as_view--->執行之後,他會將字典for迴圈解壓賦值成key,value的形式,其中通過getattr反射自己建立的類獲取value函式的記憶體地址,然後再通過setattr將key的記憶體地址替換成了value函式的記憶體地址--->執行value()-->後面的就跟View執行的流程大差不大了
# 所以說只要繼承了ViewSetMixin類,路由寫法就發生了變化,檢視類中方法可以隨意命名,只需要再路由中對映即可,也就是value值改變就可以
7.總結
首先,路由方面跟前面的大差不差,分倆個路由,唯一的區別是as_view裡面有引數,該引數是字典的形式,字典中的key代表請求方式,字典中的value代表的是該請求方式發出時候需要執行的函式。如{'get':'name','post':'egon'}
比如get請求方式發出的時候,會執行name函式,post請求發出的時候會執行egon函式。當然前提肯定是路由匹配成功,
# views.py檔案中的程式碼
from rest_framework.viewsets import ModelViewSet
class MyBooks(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = 序列化器類記憶體地址
# 路由urls.py中的程式碼
path('books/', views.MyBooks.as_view({'get':'list','post':'create'})),
path('books/<int:pk>/', views.MyBook.as_view({'get':'retrieve','put':'update','delete':'destroy'}))
需要知道每個關鍵的方法都在那個父類def list(): # 在ListModelMixin中寫了list方法 passdef create(): # 在CreateModelMixin中寫了create方法 passdef retrieve(): # 在RetrieveModelMixin中寫了retrieve方法 passdef update(): # 在UpdateModelMixin中寫了update方法 passdef destroy(): # 在DestroyModelMixin中寫了destroy方法 passdef perform_create(self,serializer): pass # 在CreateModelMixin中寫了perform_create方法 # 這個是post請求方式來的時候執行post函式中的create函式中的perform_create函式,該函式是專門建立新資料的函式def perform_destroy(self,instance): pass # 在DestroyModelMixin中寫了perform_destroy方法 # 這個是delete請求方式來的時候執行delete函式中的perform_destroy函式,該函式是專門處理刪除資料的函式
檢視集ModelViewSet-->GenericViewSet-->檢視基類GenericAPIView-->檢視基類APIView-->View-->object檢視集ModelViewSet-->GenericViewSet-->ViewSetMixin-->object檢視集ModelViewSet有6個父類