DRF 中有多種view和viewsets,我整理了一下,如下圖所示,接下來,我們分別了解下view,viewsets。
APIView
所有的view,viewsets都是繼承APIView,而APIView是繼承的django的django.views.generic.View, 然后增加了一些通用的操作,和重載了as_view
,dispatch
,options
,http_method_not_allowed
方法來適應DRF相關的配置和后續的使用。
在直接使用APIView的時候,就和使用django View一樣,分發規則也是一樣,GET請求分發到了get方法,POST請求分發到post方法, 所以路由的注冊方式也一樣。所以在這里不做演示了。
GenericAPIView
通用view的基礎視圖,其他的基礎view都是繼承了這個view,我們可以來看看源碼里面實現了那些個方法
# 為了簡化,我刪掉了注釋和具體的實現,
class GenericAPIView(views.APIView):
queryset = None # 這些會在mixins中用到
serializer_class = None
lookup_field = 'pk'
lookup_url_kwarg = None
pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
def get_queryset(self):
def get_object(self):
def get_serializer(self, *args, **kwargs):
def get_serializer_class(self):
def get_serializer_context(self):
def filter_queryset(self, queryset):
@property
def paginator(self):
def paginate_queryset(self, queryset):
def get_paginated_response(self, data):
可以看出,在這里,我們定義了queryset,serializer相關的操作。我們也可以繼承GenericAPIView 來使用定義好的一些方法。
drf-mixins
在這里,我們插入mixins這一部分,因為后面要介紹的這些view,viewset,都是使用了這種方式實現,在DRF中,有5種mixin,我們還是看看源碼里面,
# 還是刪除了多余的代碼,只看有哪些方法,
# 一共有5種mixin,分別實現列表顯示,單個資源顯示,增加,修改,刪除操作。
# 后面講解的views,veiwsets就是通過繼承不同的mixin來實現對應功能
# 在這些方法的實現中,需要用到queryset,serializers,所以使用了mixin的時候,需要在view里指定這兩個參數
class CreateModelMixin(object):
def create(self, request, *args, **kwargs):
class ListModelMixin(object):
def list(self, request, *args, **kwargs):
class RetrieveModelMixin(object):
def retrieve(self, request, *args, **kwargs):
class UpdateModelMixin(object):
def update(self, request, *args, **kwargs):
class DestroyModelMixin(object):
def destroy(self, request, *args, **kwargs):
*APIView
本部分講解以APIView結尾這這些個views,包括CreateAPIView
,ListAPIView
,RetrieveAPIView
, DestroyAPIView
,UpdateAPIView
, ListCreateAPIView
, RetrieveUpdateAPIView
, RetrieveDestroyAPIView
, RetrieveUpdateDestroyAPIView
。這些都是通過繼承GenericAPIView
和不同的mixin實現,所以我們只選擇其中的一個來作為講解,下面看看ListAPIView
中的內容
class ListAPIView(mixins.ListModelMixin,
GenericAPIView):
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
因為繼承的GenericAPIView,並沒有修改分發方式,所以也是GET請求分發到get方法,又因為繼承了ListModelMixin,所以會有list(self)方法,於是自然而然的,就在get方法中,調用self.list()去使用ListModelMixin中定義的方法。其他的views類似,都是把對應的請求轉發到合適的mixin里面。至此,drf中的views就完了。
viewsets
下面,我們來研究研究viewsets了,它不同與django原生的view,因為有修改分發方式,所以處理上會有些許的不同,還是老規矩,上源碼。
使用
class ViewSetMixin(object):
#代碼就不貼了,需要配合着看route才能理解,准備后面單獨開一篇來配合着route的處理來寫,
#在這里,我們只需要知道在這個類中,重寫了分發規則as_view(),
#規則大概來說就是,將對應的請求分發到list,create等在mixins定義了的方法中, 比如說,get請求分發到list,或者retrieve。
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
pass
class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
mixins.ListModelMixin,
GenericViewSet):
# model的只讀接口,實現了列表頁和詳情頁的
pass
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
# model 的增刪改查的接口
pass
通過源碼,我們可以發現,我們可以自己選擇繼承GenericViewSet 和對應的mixins來實現我們所需要的接口。
路由注冊
因為改了分發方式,所以,不能簡單的像之前的 path('view', View.as_view())
一樣了,我們需要像下面這樣引入route。
from myapp.views import ViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'users', ViewSet) # url 為 "/api/user/"
urlpatterns = [
path('api/', include(router.urls), name='api'),
]