DRF的基類是APIView類,GenericAPIView類是APIView類的子類。
基類是父類還是子類,GenericAPIView類有什么存在的意義呢?
其實,
他主要提供了兩個用處:
1.提供關于數據庫查詢的屬性與方法
2.提供關于序列化器使用的屬性與方法
=================================================================================================================
詳解:
先看一段小代碼比較好理解,(繼承APIView與繼承GenericAPIView的兩種不同的寫法,查詢多條數據時)
繼承APIView的寫法:
class DepartmentListAPIView(APIView):def get(self,request):"""查詢多條數據"""dep = Department.objects.all()# 創建序列化器對象serializer = DepartmentSerializer(instance=dep,many=True)# 序列化:對象->字典data_dict = serializer.data# DRF的Response對象可以把字典轉換為請求頭指定的格式返回return Response(data=data_dict)
?
繼承GenericAPIView的寫法:
class DepartmentListAPIView(GenericAPIView):# querset與serializer_class是固定名字的!一定要指定# queryset指定數據庫全部數據的查詢集queryset = Department.objects.all()# serializer_class指定序列化器serializer_class = DepartmentSerializerdef get(self,request):"""查詢多條數據"""dep = self.get_queryset()serializer = self.get_serializer(dep,many=True)data_dict = serializer.datareturn Response(data=data_dict)
?
1.提供關于數據庫查詢的屬性與方法:
上面例子中,get_queryset()的方法,可以取得數據庫查詢結果的查詢集queryset的內容。(注意,一定要通過get_query取得數據庫查詢的結果后再傳給序列化器,不能直接傳self.queryset給序列化器,因為get_query的源碼還有“Ensure queryset is re-evaluated on each request.”這一個步驟。)
?
2.提供關于序列化器使用的屬性與方法、
上面的列子中,get_serializer()的方法,實際上就是取類屬性serializer_class的值
?
-
更多的繼承APIView與繼承GenericAPIView的寫法:
繼承APIView的寫法:
class DepartmentListAPIView(APIView):def get(self,request):"""查詢多條數據"""dep = Department.objects.all()# 創建序列化器對象serializer = DepartmentSerializer(instance=dep,many=True)# 序列化:對象->字典data_dict = serializer.data# DRF的Response對象可以把字典轉換為請求頭指定的格式返回return Response(data=data_dict)def post(self,request):"""新增一條數據"""# DRF的Request對象直接把接受到的值轉換為字典data_dict = request.data# 創建序列化器對象serializer = DepartmentSerializer(instance=None,data=data_dict)# 校驗校驗不通過,拋異常(反序列化的功能)serializer.is_valid(raise_exception=True)# 反序列化,把字典的數據存進數據庫 serializer.save()# restful風格,新增要返回新增數據的那一列內容。用了序列化,把對象轉換為字典,同時Response處理。return Response(data=serializer.data)class DepartmentDetailAPIView(APIView):def get(self,request,pk):"""查詢一條數據"""# 查詢出該條數據的對象try:dep = Department.objects.get(id=pk)except Department.DoesNotExist:return HttpResponse(status=status.HTTP_404_NOT_FOUND)# 創建序列化器對象serializer = DepartmentSerializer(instance=dep)# 序列化,把對象轉換為字典,同時Response根據請求頭返回相應的格式return Response(data=serializer.data)def post(self,request,pk):"""修改部門"""# DRF的Request對象直接把接受到的值轉換為字典data_dict = request.data# 查詢出要修改的數據try:dep = Department.objects.get(id=pk)except Department.DoesNotExist:return HttpResponse(status=404)# 創建序列化器對象serializer = DepartmentSerializer(instance=dep,data=data_dict)# 反序列化,校驗參數是否正確,若不正確,拋異常serializer.is_valid(raise_exception=True)# 反序列化,把字典的數據存進數據庫 serializer.save()# 序列化,把對象轉換為字典。同時DRF的Response對象根據請求頭返回相應的格式return Response(serializer.data)def delete(self,request,pk):"""刪除一個部門"""try:dep = Department.objects.get(id=pk)except Department.DoesNotExist:return HttpResponse(status=404)dep.delete()return Response(status=status.HTTP_204_NO_CONTENT)
?
繼承GenericAPIView的寫法:
class DepartmentListAPIView(GenericAPIView):# querset與serializer_class是固定名字的!# queryset指定數據庫全部數據的查詢集queryset = Department.objects.all()# serializer_class指定序列化器serializer_class = DepartmentSerializerdef get(self,request):"""查詢多條數據"""dep = self.get_queryset()serializer = self.get_serializer(instance=dep,many=True)data_dict = serializer.datareturn Response(data=data_dict)def post(self,request):"""新增一條數據"""data_dict = request.dataserializer = self.get_serializer(instance=None,data=data_dict)serializer.is_valid(raise_exception=True)serializer.save()return Response(serializer.data)class DepartmentDetailAPIView(GenericAPIView):queryset = Department.objects.all()serializer_class = DepartmentSerializerdef get(self,request,pk):"""查詢一條數據"""dep = self.get_object() # 有主鍵用get_object(),get_object()方法根據pk參數查找queryset中的數據對象serializer = self.get_serializer(instance=dep)return Response(data=serializer.data)def post(self,request,pk):"""修改部門"""data_dict = request.datadep = self.get_object()serializer = self.get_serializer(instance=dep,data=data_dict)serializer.is_valid(raise_exception=True)serializer.save()return Response(serializer.data)def delete(self,request,pk):"""刪除一個部門"""dep = self.get_object()dep.delete()return Response(status=status.HTTP_204_NO_CONTENT)
?
?
- 總結:
從上面的代碼可以看出,繼承APIView和繼承GenerciAPIView的代碼量基本差不多。那么GenericAPIView這個類有什么實質的用處呢?
其實,
他是只是為了提供幾種方法給它的擴展類而已,GenericAPIView通常結合一個或多個Mixin擴展類使用,用來快速地實現列表視圖與詳情視圖。
?