1. 程式人生 > >DRF檢視集的使用

DRF檢視集的使用

# 原創,轉載請留言聯絡

 

如果要把同一種http請求方法的多個介面放在同一個檢視中,比如:查詢多條資料和一條資料都是get請求,放在同一個視圖裡,應該怎麼做呢???

如果直接放在一起,會怎樣呢?

# 檢視:
class DepartmentTestView(ListAPIView, RetrieveAPIView):
    queryset = Department.objects.all()
    serializer_class = DepartmentSerializer

# 路由:
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r
'^departments$',views.DepartmentTestView.as_view()), url(r'^departments/(?P<pk>\d+)$',views.DepartmentTestView.as_view()) ]

當訪問/departments時,匹配對路由,然後到達檢視,找get請求的檢視,先找到了ListAPIView,執行,正確的返回了資料。

當訪問/departments/1時,匹配對路由,然後到達檢視,找get請求的檢視,先找到ListAPIView,執行,返回了查詢全部資料的結果。不是我們想要的結果。

解決辦法:使用檢視集

 

1.ViewSet

  • 繼承自APIView與ViewSetMixin
  • 繼承ViewSetMixin的作用是實現在呼叫as_view()時傳入字典(如{'get':'list'})的對映處理工作。
  • 在ViewSet中,沒有提供任何 action方法,需要我們自己實現 action方法(和繼承APIView一樣,要自己建立序列化器物件,自己校驗資料,自己存資料庫,自己序列化等...)

 示例:

首先是檢視的程式碼:

class DepartmentViewSet(ViewSet):
    def list(self,request):
        
"""查詢全部部門""" dep = Department.objects.all() serializer = DepartmentSerializer(instance=dep,many=True) return Response(data=serializer.data) def create(self,request): """新增一個部門""" data_dict = request.data serializer = DepartmentSerializer(instance=None,data=data_dict) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data) def retrieve(self,request,pk): """查詢一個部門""" try: dep = Department.objects.get(id=pk) except Department.DoesNotExist: return Response(status=status.HTTP_404_NOT_FOUND) serializer = DepartmentSerializer(instance=dep) return Response(serializer.data) def update(self,request,pk): """修改一個部門""" try: dep = Department.objects.get(id=pk) except Department.DoesNotExist: return Response(status=status.HTTP_404_NOT_FOUND) data_dict = request.data serializer = DepartmentSerializer(instance=dep,data=data_dict) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data) def delete(self,request,pk): """刪除一個部門""" try: dep = Department.objects.get(id=pk) except Department.DoesNotExist: return Response(status=status.HTTP_404_NOT_FOUND) dep.delete() return Response(status=status.HTTP_204_NO_CONTENT)

 

然後是路由的配置:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^departments$',views.DepartmentViewSet.as_view({'get':'list','post':'create'})),
    url(r'^departments/(?P<pk>\d+)$',views.DepartmentViewSet.as_view({'get':'retrieve','post':'update','delete':'delete'}))
]

 

注意:

函式名(list、create、retrieve、update、delete)可以自定義的,也可以根據實際情況定義函式。

 

2.GenericViewSet

  • 使用ViewSet通常並不方便,因為list、retrieve、create、update、destory等方法都需要自己編寫
  • 因為這些方法與前面講過的Mixin擴充套件類提供的方法同名,所以我們可以通過繼承Mixin擴充套件類來複用這些方法,而Mixin擴充套件類依賴與GenericAPIView,所以還需要繼承GenericAPIView
  • GenericViewSet就幫助我們完成了這樣的繼承工作,繼承自GenericAPIView與ViewSetMixin,在實現了呼叫as_view()時傳入字典(如{'get':'list'})的對映處理工作的同時,還提供了GenericAPIView提供的基礎方法,可以直接搭配Mixin擴充套件類使用。

 

示例:

首先是檢視的程式碼:

class DepartmentViewSet(ListModelMixin,CreateModelMixin,RetrieveModelMixin,
                        UpdateModelMixin,DestroyModelMixin,GenericViewSet):

    queryset = Department.objects.all()
    serializer_class = DepartmentSerializer

 

然後是路由的配置:

urlpatterns = [
    url(r'^departments$',views.DepartmentViewSet.as_view({'get':'list','post':'create'})),
    url(r'^departments/(?P<pk>\d+)$',views.DepartmentViewSet.as_view({
        'get':'retrieve','put':'update','delete':'destroy'
    }))
]

 

注意:

路由配置中,例如'get':'list',對應的是請求方法,ListModelMixin裡面的方法。特別是‘list’,一定要點進類裡面,看下方法名是什麼,再寫在路由裡面,不然無法呼叫類裡面的方法,也就返回不了響應物件。

拓展:

如果這幾個類滿足不了需求,可以仿照ViewSet的方法自定義方法。如果自定義的方法要用到不同的序列話器,可以這樣做:

 

def get_serializer_class(self): """修改部門名稱的介面,使用不同的序列化器""" if self.action == '[方法名]': return [自定義的序列器] else: return DepartmentSerializer

 

3.ModelViewSet

  • 繼承自GenericViewSet
  • 包括了 ListModelMixinRetrieveModelMixinCreateModelMixinUpdateModelMixinDestroyModelMixin
  • 和第2點的用法一樣

 

4.ReadOnlyModelViewSet

  • 繼承自 GenericViewSet
  • 包括了 ListModelMixinRetrieveModelMixin
  • 和第2點的用法一樣