目錄
3.5個檢視擴充套件類:ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
4.GenericAPIView的檢視子類:ListAPIView,CreateAPIView,RetrieveAPIView,UpdateAPIView,DestroyAPIView
5.檢視集基類:ViewSet,GenericViewSet,ModelViewSet,ReadOnlyViewSet
3.DefaultRouter和SimpleRouter的區別(瞭解)
APIView
APIView總結
1.APIView中封裝了自己的request和response
2.django:request.GET對應drf中的request.query_params
3.django:request.POST對應drf中的request.data
4.APIView中的response不需要寫引數safe=False,ensure_ascii這些東西了,因為這些功能已經封裝在response裡面了
5.當我們在瀏覽器上訪問一個url,給你回覆的是一個介面。如果我們用postman訪問url,給你返回的就是json資料。這是因為response中有相關配置導致的。
APIView實現程式碼
class Students1View(APIView): # 獲取所有資料介面 def get(self,request): all_data = models.Student.objects.all() # 獲取資料庫中Student表中所有資料 serializer = StudentSerializer(instance=all_data,many=True) # 將後端資料序列化 return Response(serializer.data) # 將序列化之後的資料傳遞給前端 # 新增一條記錄的介面 def post(self,request): data = request.data # 獲取使用者在前端輸入的資料 serializer = StudentSerializer(data=data) # 將資料反序列化 if serializer.is_valid(): # 校驗 instance = serializer.save() # instance為新增的新紀錄物件 serializer = StudentSerializer(instance=instance) # 根據API規範,資料儲存之後應該顯示到前端上,所以需要將新新增的資料序列化 return Response(serializer.data,status=status.HTTP_201_CREATED) else: print(serializer.errors) class Student1View(APIView): # 獲取單條記錄 def get(self,request,pk): stu_obj = models.Student.objects.get(pk=pk) serializer = StudentSerializer(instance=stu_obj) return Response(serializer.data) # 更新單條記錄 def put(self,request,pk): stu_obj = models.Student.objects.get(pk=pk) data = request.data serializer = StudentSerializer(instance=stu_obj, data=data, partial=True) if serializer.is_valid(): instance = serializer.save() # instance為新增的新紀錄物件 serializer = StudentSerializer(instance=instance) return Response(serializer.data) else: print(serializer.errors) # 刪除單條記錄 def delete(self,request,pk): models.Student.objects.get(pk=pk).delete() return Response(None,status=status.HTTP_204_NO_CONTENT)
GenericAPIView:通用檢視類
GenerivAPIView繼承自APIView方法,
from rest_framework.generics import GenericAPIView class Students2View(GenericAPIView,): queryset = models.Student.objects.all() # 指明要使用的資料查詢集[必須指定] serializer_class = StudentSerializer # 指明檢視要使用的序列化器[可寫可不寫] # 通過get_serializer_class來控制不同條件下,使用不同的序列化器類 def get_serializer_class(self): if self.request.method == 'GET': return Student2Serializer else: return StudentSerializer # 獲取所有資料介面 def get(self, request): # all_data = models.Student.objects.all() # serializer = StudentSerializer(instance=all_data, many=True) serializer = self.get_serializer(instance=self.get_queryset(), many=True) return Response(serializer.data) # 新增一條記錄的介面 def post(self, request): data = request.data serializer = self.get_serializer(data=data) if serializer.is_valid(): instance = serializer.save() # instance為新增的新紀錄物件 serializer = self.get_serializer(instance=instance) return Response(serializer.data, status=status.HTTP_201_CREATED) else: print(serializer.errors) return Response({'error':'欄位錯誤'}) class Student2View(GenericAPIView): queryset = models.Student.objects.all() serializer_class = StudentSerializer # 獲取單條記錄 def get(self, request, pk): # stu_obj = models.Student.objects.get(pk=pk) serializer = self.get_serializer(instance=self.get_object()) return Response(serializer.data) # 更新單條記錄 def put(self, request, pk): # stu_obj = models.Student.objects.get(pk=pk) data = request.data serializer = self.get_serializer(instance=self.get_object(), data=data, partial=True) if serializer.is_valid(): # print('>>>',serializer.data) #在save方法之前,不能呼叫data屬性,serializer.data instance = serializer.save() # instance為新增的新紀錄物件 print(serializer.data) #之後可以看 serializer = self.get_serializer(instance=instance) return Response(serializer.data) else: print(serializer.errors) # 刪除單條記錄 def delete(self, request, pk): models.Student.objects.get(pk=pk).delete() return Response(None, status=status.HTTP_204_NO_CONTENT)
GenericAPIView中的屬性和方法
在檢視中可以呼叫該方法獲取詳情資訊的模型類物件。
返回序列化器類,預設返回
5個檢視擴充套件類:????ModelMixin
這五個擴充套件類需要搭配GenericAPIView父類,因為五個擴充套件類的實現需要呼叫GenericAPIView提供的序列化器與資料庫查詢的方法。
換句話說。就是你在檢視中的get post put等這些方法中不用寫裡面的程式碼了,裡面的程式碼相關的操作已經被封裝到對應的Mixin中了。
class Students3View(GenericAPIView,ListModelMixin,CreateModelMixin): queryset = models.Student.objects.all() serializer_class = StudentSerializer # 獲取所有資料介面 def get(self, request): return self.list(request) # 新增一條記錄的介面 def post(self, request): return self.create(request) class Student3View(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin): queryset = models.Student.objects.all() serializer_class = StudentSerializer # 獲取單條記錄 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)
GenericAPIView的檢視子類:????APIView
上面的程式碼還是過於麻煩,因為既要繼承GenericAPIView又要繼承Mixin系列的類。
所以將各自的操作封裝成自己的APIView類。用哪個繼承哪個。
而且連函式都不用寫了,在???APIView類中已經有了,所以不用再寫了,繼承自己的APIView類即可。
from rest_framework.generics import ListAPIView,CreateAPIView,RetrieveAPIView,UpdateAPIView,DestroyAPIView class Students4View(ListAPIView,CreateAPIView): queryset = models.Student.objects.all() serializer_class = StudentSerializer class Student4View(RetrieveAPIView,UpdateAPIView,DestroyAPIView): queryset = models.Student.objects.all() serializer_class = StudentSerializer
檢視集基類:ViewSet,GenericViewSet,ModelViewSet,ReadOnlyViewSet
ViewSet
主要解決問題:之前我們在寫檢視類的時候,獲取多條資料和提交資料放在了一個類中。獲取單條資料,更新單條資料,刪除多條資料放到了一個類中
這是因為多條資料操作時不需要指定pk值,而針對單條資料時,需要指定pk值。也就是說需要知道你要操作哪一條資料
這樣我們就很矛盾。我們沒法將5個方法放到同一個類中。
而下面的ViewSet就可以解決這個問題,將5個方法放到同一個類中
from rest_framework.viewsets import ViewSet class Students5View(ViewSet): # 獲取所有資料介面 def get_all_student(self,request): # action all_data = models.Student.objects.all() serializer = StudentSerializer(instance=all_data,many=True) return Response(serializer.data) # 新增一條記錄的介面 def add_student(self,request): data = request.data serializer = StudentSerializer(data=data) if serializer.is_valid(): instance = serializer.save() #instance為新增的新紀錄物件 serializer = StudentSerializer(instance=instance) return Response(serializer.data,status=status.HTTP_201_CREATED) else: print(serializer.errors) def get_one(self,request,pk): stu_obj = models.Student.objects.get(pk=pk) serializer = StudentSerializer(instance=stu_obj) return Response(serializer.data)
通過上面程式碼我們可以看出。單條資料操作和多條資料被放到了一個類中。並且方法名也不再侷限於必須要使用get post put...這些方法名了。
這是因為在urls.py中的as_view方法做了一個請求方法和對應函式名的指定。
而獲取單條資料和獲取多條資料能夠共存在一個類中,是因為他們處於兩個url中。雖然都是get請求過去的,但是他們在不同的url中,會執行各自的檢視方法
通過下面url,我們就可以發揮出ViewSet的用處了:
path('students5/', views.Students5View.as_view({'get':'get_all_student','post':'add_student'})), re_path('students5/(?P<pk>\d+)/', views.Students5View.as_view({'get':'get_one'})),
ViewSet+????APIView
用我們剛才學的ViewSet和之前的???APIView做一個結合~
效果:即放到了一個類中,而且各個方法裡不用寫詳細程式碼(????APIView的作用)
"""發揮下ViewSet的作用""" from rest_framework.viewsets import ViewSet from rest_framework.generics import ListAPIView,CreateAPIView,RetrieveAPIView class Student2ViewSet(ViewSet,ListAPIView,CreateAPIView,RetrieveAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer
def get_all(self,request): return self.list(request) def add_student(self,request): return self.create(request) def get_one(self,request,pk): return self.retrieve(request)
GenericViewSet+???Mixin
效果和Viewset+???APIView是相同的
from rest_framework.viewsets import GenericViewSet from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin class Student3ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin): queryset = Student.objects.all() serializer_class = StudentModelSerializer def get_all(self,request): return self.list(request) def add_student(self,request): return self.create(request) def get_one(self,request,pk): return self.retrieve(request)
現在我們的程式碼是這個樣子的。美中不足是我們還需要自己寫def方法,其實我們希望的是類裡面沒有def方法的
其實。這個需求剛才在前面已經提到了。
只需要在urls.py中將get post put這類請求型別直接與Mixin中內建的list,create,update等動作方法關聯起來。
這樣它就會自動去執行裡面的list,create,update方法。不需要你在檢視裡定義一個函式名稱然後再return self.create()了。
urls.py如下所示:
urlpatterns = [ path("students7/", views.Student4ViewSet.as_view({"get": "list", "post": "create"})), re_path("students7/(?P<pk>\d+)/", views.Student4ViewSet.as_view({"get": "retrieve","put":"update","delete":"destroy"})), ]
url直接就是{請求型別:action動作名},這樣我們在檢視那一塊的程式碼又可以縮減了。函式全部無需定義了。
經過改良後,檢視程式碼如下所示:
from rest_framework.viewsets import GenericViewSet from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin class Student4ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin): queryset = Student.objects.all() serializer_class = StudentModelSerializer
ModelViewSet
上面的程式碼,在匯入和繼承的時候太麻煩了,需要寫5個Mixin類
這時出現了ModelViewSet,ModelViewSet同時繼承ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin這五個類。
這樣寫起來就更加簡單了。
終極版如下所示:
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet from rest_framework.decorators import action class StudentModelViewSet(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer
ReadOnlyViewset
舉例,比如做一個登入方法login:
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet class StudentModelViewSet(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer def login(self,request): # 這個就可以稱為自定義的action動作 """學生登入功能""" return Response({"message":"登入成功"})
urls.py這樣寫
urlpatterns = [ path("students8/", views.StudentModelViewSet.as_view({"get": "list", "post": "create"})), re_path("students8/(?P<pk>\d+)/", views.StudentModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})), path("stu/login/",views.StudentModelViewSet.as_view({"get":"login"})) ]
在檢視集中,我們可以通過action物件屬性來獲取當前請求檢視集時的action動作是哪個。
from rest_framework.viewsets import ModelViewSet from students.models import Student from .serializers import StudentModelSerializer from rest_framework.response import Response class StudentModelViewSet(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer def get_new_5(self,request): """獲取最近新增的5個學生資訊""" # 運算元據庫 print(self.action) # 獲取本次請求的檢視方法名 '''通過路由訪問到當前方法中.可以看到本次的action就是請求的方法名'''
路由:Routers
如何新增路由資料
如何新增路由資料,並且和檢視函式做關聯:
from django.urls import path, re_path from . import views urlpatterns = [ ... ] """使用drf提供路由類router給檢視集生成路由列表""" # 例項化路由類 # drf提供一共提供了兩個路由類給我們使用,他們用法一致,功能幾乎一樣 from rest_framework.routers import DefaultRouter router = DefaultRouter() # 註冊檢視集 # router.register("路由字首",檢視集類) router.register("router_stu",views.StudentModelViewSet) # 把生成的路由列表追加到urlpatterns urlpatterns += router.urls
所以我們如果也要給自定義方法生成路由,則需要進行action動作的宣告。
在檢視集中附加action宣告
以action裝飾器裝飾的方法名會作為action動作名,與list、retrieve等同。
action裝飾器可以接收兩個引數:
-
methods: 宣告該action對應的請求方式,列表傳遞
-
detail:
宣告該action的路徑是否與單一資源對應,及是否是
xxx/<pk>/action方法名/
-
True 表示路徑格式是
xxx/<pk>/action方法名/
-
False 表示路徑格式是
-
from rest_framework.viewsets import ModelViewSet from rest_framework.decorators import action class StudentModelViewSet(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer # methods 設定當前方法允許哪些http請求訪問當前檢視方法 '''detail 設定當前檢視方法是否是操作一個資料''' # detail為True,表示路徑名格式應該為 router_stu/{pk}/login/ @action(methods=['get'], detail=True) def login(self, request,pk): """登入""" ... # detail為False 表示路徑名格式應該為 router_stu/get_new_5/ @action(methods=['put'], detail=False) def get_new_5(self, request): """獲取最新新增的5個學生資訊""" ...
DefaultRouter和SimpleRouter的區別(瞭解)
建立虛擬環境
1.安裝虛擬環境
# 1.管理員方式開啟終端 # 2.安裝虛擬環境 pip install virtualenv -i https://pypi.douban.com/simple # 3.終端關閉,再重新開啟 # 4.注意:建立[環境名稱]資料夾,放置所有的環境,進入指定目錄 D:/envs # 5.建立虛擬環境 virtualenv 環境名稱 'C:\python\python3.6.exe' '''這樣寫的前提是你的電腦已經將python加入到環境變數中''' virtualenv 環境名稱 --python=python3.6
2.啟用虛擬環境
# 1.進入到虛擬環境資料夾下的Scripts目錄 activate '''啟用虛擬環境''' # 2.退出虛擬環境 deactivate '''退出虛擬環境'''
3.在虛擬環境中安裝模組
# 1.啟用虛擬環境 # 2.在啟用的虛擬環境中安裝模組 pip3 install django==2.2 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com # 3.搭建專案環境,在pycharm選擇直譯器時,選擇你之前已經建立好的虛擬環境
4.在pycharm上使用虛擬環境
附:APIView思維導圖
附:drf的執行流程圖