Django(58)viewsets視圖集詳解


前言

ViewSet 只是一種基於類的視圖,它不提供任何方法處理程序(如 .get().post()),而是提供諸如.list().create() 之類的操作。
ViewSet 的方法處理程序僅使用 .as_view() 方法綁定到完成視圖的相應操作。
通常不是在urlconf中的視圖集中顯示注冊視圖,而是要使用路由類注冊視圖集,該類會自動為你確定 urlconf
 

源碼分析

我們首先看一下viewsets.py文件的源碼結構,如下圖

我們可以看到有5個類

  • ViewSetMixin
  • ViewSet:繼承自ViewSetMixinAPIView
  • GenericViewSet:繼承自ViewSetMixinGenericAPIView
  • ReadOnlyModelViewSet:繼承自RetrieveModelMixinListModelMixinGenericViewSet
  • ModelViewSet:繼承自5大mixins工具類和GenericViewSet
     

ViewSetMixin

通過上述代碼結構分析,我們了解到只要知道ViewSetMixin是干嘛的,其他的類都繼承於它。從源碼中我們知道,ViewSetMixin重寫了as_view()方法,源碼如下:

def as_view(cls, actions=None, **initkwargs):
    """
    由於基於類的視圖圍繞實例化視圖創建閉包的方式,我們需要完全重新實現`.as_view`,並稍微修改創建和返回的視圖函數。 
    對於某些路由配置,initkwargs 的名稱和描述可能會被明確覆蓋,例如,額外操作的名稱。
    """
    # 名稱和描述 initkwargs 可能會被顯式覆蓋
    cls.name = None
    cls.description = None
    
    # 后綴 initkwarg 保留用於顯示視圖集類型。如果提供了名稱,則此 initkwarg 應該無效。
    cls.suffix = None

    cls.detail = None
    
    # 設置 basename 允許視圖反轉其操作 url。該值由路由器通過 initkwargs 提供。
    cls.basename = None
    
    # actions必須不能為空,否則報錯
    if not actions:
        raise TypeError("The `actions` argument must be provided when "
                        "calling `.as_view()` on a ViewSet. For example "
                        "`.as_view({'get': 'list'})`")

    # 清理關鍵字參數
    for key in initkwargs:
        if key in cls.http_method_names:
            raise TypeError("You tried to pass in the %s method name as a "
                            "keyword argument to %s(). Don't do that."
                            % (key, cls.__name__))
        if not hasattr(cls, key):
            raise TypeError("%s() received an invalid keyword %r" % (
                cls.__name__, key))
    
    # name和suffix是互斥的
    if 'name' in initkwargs and 'suffix' in initkwargs:
        raise TypeError("%s() received both `name` and `suffix`, which are "
                        "mutually exclusive arguments." % (cls.__name__))
    
    def view(request, *args, **kwargs):
        self = cls(**initkwargs)

        if 'get' in actions and 'head' not in actions:
            actions['head'] = actions['get']

        self.action_map = actions
        
        # 將方法綁定到actions, 這是與標准視圖不同的一點
        for method, action in actions.items():
            handler = getattr(self, action)
            setattr(self, method, handler)

        self.request = request
        self.args = args
        self.kwargs = kwargs

        return self.dispatch(request, *args, **kwargs)

    update_wrapper(view, cls, updated=())

    update_wrapper(view, cls.dispatch, assigned=())

    view.cls = cls
    view.initkwargs = initkwargs
    view.actions = actions
    return csrf_exempt(view)

從上述源碼中了解到,ViewSetMixin重寫了as_view方法,as_view是將請求的方法綁定到了actions
 

ViewSet

class ViewSet(ViewSetMixin, views.APIView):
    """
    默認情況下,基本 ViewSet 類不提供任何操作。
    """
    pass

ViewSet繼承了ViewSetMixinAPIView,增刪改查需要我們自己定義
 

GenericViewSet

class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
    """
    GenericViewSet 類默認不提供任何操作,但包含通用視圖行為的基本集,例如`get_object` 和`get_queryset` 方法。
    """
    pass

GenericViewSet類相比ViewSet,包含了一些視圖行為的通用方法
 

視圖集特點

  1. 視圖集都是優先繼承ViewSetMixin類,再繼承一個視圖類(GenericAPIView或APIView)
  2. ViewSetMixin提供了重寫的as_view()方法,繼承視圖集的視圖類,配置路由時調用as_view()必須傳入 請求-函數名 映射關系字典
    eg: path('v1/books/<int:pk>/', views.BookGenericViewSet.as_view({"get": "my_get_obj"}))
     

GenericAPIView與APIView 作為兩大繼承視圖的區別

  1. GenericViewSetViewSet都繼承了ViewSetMixinas_view都可以配置 請求-函數 映射
  2. GenericViewSet繼承的是GenericAPIView視圖類,用來完成標准的model類操作接口
  3. ViewSet繼承的是APIView視圖類,用來完成不需要model類參與,或是非標准的model類操作接口
    post請求在標准的model類操作下就是新增接口,登陸的post不滿足
    post請求驗證碼接口,不需要model類的參與
    案例:登陸的post請求,並不是完成數據的新增,只是用post提交數據,得到的結果也不是登陸的用戶信息,而是登陸的認證信息
     

ReadOnlyModelViewSet

class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
                           mixins.ListModelMixin,
                           GenericViewSet):
    """
    提供默認`list()` 和`retrieve()` 操作的視圖集。
    """
    pass

 

ModelViewSet

class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    """
    一個提供默認 `create()`、`retrieve()`、`update()`、`partial_update()`、`destroy()` 和 `list()` 操作的視圖集。
    """
    pass

 

實戰案例

視圖函數如下

class StudentViewSets(viewsets.ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    def my_get(self, request, *args, **kwargs):
        response =  self.retrieve(request, *args, **kwargs)
        return APIResponse(results=response.data)

    def my_list(self, request, *args, **kwargs):
        response = self.list(request, *args, **kwargs)
        return APIResponse(results=response.data)

我們繼承自ModelViewSet,自帶5個mixins工具,我們定義了2個查詢方法,然后在urls中配置

urlpatterns = [
    path('v2/student/<int:pk>/', views.StudentViewSets.as_view({"get": "my_get"})),
    path('v2/student/', views.StudentViewSets.as_view({"get": "my_list"})),
]

as_view中添加了get請求方式的方法,有pk調用my_get代表單查,沒有pk調用my_list代表群查,這樣寫的原因就是我們的StudentViewSets繼承了ViewSetMixin


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM