urlpatterns = [ ... re_path(r'^authors/$', views.AuthorView.as_view(), name="author"), re_path(r'^authors/(?P<pk>\d+)/$', views.AuthorDetailView.as_view(), name="detail_author") ]
/app01/serializer.py:前端
class AuthorModelSerializers(serializers.ModelSerializer): class Meta: model = Author fields = "__all__"
# Author from rest_framework import mixins, generics class AuthorView(mixins.ListModelMixin, # 擴展了列出查詢集功能 mixins.CreateModelMixin, # 擴展了建立和保存新模型實例功能 generics.GenericAPIView): # 繼承擴展了REST框架的APIView類,爲標準列表和詳細視圖添加了常見的行爲 queryset = Author.objects.all() # 配置queryset:告知這個類此次處理的數據 serializer_class = AuthorModelSerializers # 告知處理用到的序列化組件 def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs) class AuthorDetailView(mixins.RetrieveModelMixin, # 擴展在響應中實現返回現有模型實例功能(獲取單條數據) mixins.DestroyModelMixin, # 擴展示有模型實例的刪除功能 mixins.UpdateModelMixin, # 擴展更新和保存現有模型實例功能 generics.GenericAPIView): queryset = Author.objects.all() # 配置queryset:告知這個類此次處理的數據 serializer_class = AuthorModelSerializers # 告知處理用到的序列化組件 def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs) def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs)
注意:node
這兩個變量是必須的。queryset告知這個類此次處理的數據。serializer_class告知這個類數據處理用到的序列化組件。python
這個類擴展了REST框架的APIView
類,爲標準列表和詳細視圖添加了常見的行爲。數據庫
提供的每一個具體的通用視圖都是經過把GenericAPIView
與一個或多個mixin類進行組合來構建的。django
# 方式三:基於rest_framework框架實現序列化(pip install djangorestframework) from rest_framework.views import APIView from rest_framework.response import Response from .serializers import BookSerializer # 自定義序列化類 class BookView(APIView): query_set = Book.objects.all() # 將query_set抽離 serializer_class = BookSerializer # 拿到序列化器 def get(self, request): # 第一個圖書對象 # book_obj = Book.objects.first() # ret = BookSerializer(book_obj) # book_list = Book.objects.all() book_list = self.query_set # ret = BookSerializer(book_list, many=True) # 使用序列化器序列化 ret = self.serializer_class(book_list, many=True) """ 序列化的數據保存在ret.data中 """ return Response(ret.data) """ 得出來的結果會使用Django REST framework模板,在serializers.py中定製好序列化類後,顯示效果以下所示: HTTP 200 OK Allow: GET, HEAD, OPTIONS Content-Type: application/json Vary: Accept [ { "id": 1, "title": "python開發", "category": "Python", "pub_time": "2011-08-27", "publisher": { "id": 1, "title": "人民日報社" }, "author": [ { "id": 1, "name": "xxx" }, { "id": 2, "name": "sssxx" } ] }, ... ] """ def post(self, request): print(request.data) serializer = BookSerializer(data=request.data) # 序列化器校驗前端傳回來的數據 if serializer.is_valid(): serializer.save() # 驗證成功後保存數據庫 # 由於ModelSerializer的create方法不支持source的用法。所以必須還自定義一個create方法。 return Response(serializer.validated_data) # validated_data存放驗證經過的數據 else: return Response(serializer.errors) # errors存放錯誤信息 ''' 發送post請求接口設計 POST /books/list { "title": "nodejs的使用教程", "w_category": "1", "pub_time": "2018-10-27", "publisher_id": 1, "author_list": [1,2,3] } ''' class BookEditView(APIView): def get(self, request, id): """查看單條數據""" book_obj = Book.objects.filter(id=id).first() ret = BookSerializer(book_obj) return Response(ret.data) ''' GET /books/retrieve/3 { "id": 3, "title": "Linux開發", "category": "Linux", "pub_time": "2008-08-27", "publisher": { "id": 3, "title": "長江日報社" }, "author": [ { "id": 1, "name": "阿薩德" }, { "id": 3, "name": "阿斯達" } ] } ''' def put(self, request, id): """更新操做""" book_obj = Book.objects.filter(id=id).first() serializer = BookSerializer( book_obj, # 待更新對象 data=request.data, # 要更新的數據 partial=True # 重點:進行部分驗證和更新 ) if serializer.is_valid(): serializer.save() # 保存 return Response(serializer.validated_data) # 返回驗證經過的數據 # return Response(serializers.data) # 返回全部數據 else: return Response(serializer.errors) # 返回驗證錯誤的數據 def delete(self, request, id): """刪除操做""" book_obj = Book.objects.filter(id=id).first() book_obj.delete() return Response("")
升級:改寫使用通用類,繼承通用方法。json
class GenericAPIView(APIView): # 通用APIView模板類 query_set = None serializer_class = None def get_queryset(self): return self.query_set def get_serializer(self, *args, **kwargs): return self.serializer_class(*args, **kwargs) # 實例化,且接收全部的參數 class BookView(GenericAPIView): # 以方法的形式調用獲取 query_set = Book.objects.all() serializer_class = BookSerializer def get(self, request): book_list = self.get_queryset() ret = self.get_serializer(book_list, many=True) return Response(ret.data) def post(self, request): serializer = BookSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) else: return Response(serializer.errors)
class GenericAPIView(APIView): # 通用APIView模板類 query_set = None serializer_class = None def get_queryset(self): return self.query_set def get_serializer(self, *args, **kwargs): return self.serializer_class(*args, **kwargs) # 實例化,且接收全部的參數 class ListModelMixin(object): def list(self, request): queryset = self.get_queryset() ret = self.get_serializer(queryset, many=True) return Response(ret.data) class CreateModelMixin(object): def create(self, request): serializer = self.get_serializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) else: return Response(serializer.errors) class RetrieveModelMixin(object): def retrieve(self, request, id): # 查看單條數據 book_obj = self.get_queryset().filter(id=id).first() ret = self.get_serializer(book_obj) return Response(ret.data) class UpdateModelMixin(object): def update(self, request, id): book_obj = self.get_queryset().filter(id=id).first() serializer = self.get_serializer( book_obj, # 待更新對象 data=request.data, # 要更新的數據 partial=True # 重點:進行部分驗證和更新 ) if serializer.is_valid(): serializer.save() # 保存 return Response(serializer.validated_data) # 返回驗證經過的數據 # return Response(serializers.data) # 返回全部數據 else: return Response(serializer.errors) # 返回驗證錯誤的數據 class DestroyModelMixin(object): def delete(self, request, id): book_obj = self.get_queryset().filter(id=id).first() book_obj.delete() return Response("") class BookView(GenericAPIView, ListModelMixin, CreateModelMixin): # 一層封裝 query_set = Book.objects.all() serializer_class = BookSerializer def get(self, request): return self.list(request) def post(self, request): return self.create(request) class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): # 一層封裝 query_set = Book.objects.all() serializer_class = BookSerializer def get(self, request, id): """查看單條數據""" return self.retrieve(request, id) def put(self, request, id): """更新操做""" return self.update(request, id) def delete(self, request, id): """刪除操做""" return self.destroy(request, id)
進一步封裝以下所示:api
# 二層封裝 class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin): pass class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): pass # class BookView(GenericAPIView, ListModelMixin, CreateModelMixin): # 一層封裝 class BookView(ListCreateAPIView): # 使用二層封裝 query_set = Book.objects.all() serializer_class = BookSerializer def get(self, request): return self.list(request) def post(self, request): return self.create(request) # class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): # 一層封裝 class BookEditView(RetrieveUpdateDestroyAPIView): # 使用二層封裝 query_set = Book.objects.all() serializer_class = BookSerializer def get(self, request, id): """查看單條數據""" return self.retrieve(request, id)
通過兩次封裝後,剩下兩個視圖,但依然不夠簡潔。因爲兩個get請求的返回值不一樣,寫了兩個視圖來解決。app
如今能夠經過路由傳參的方式來解決上述問題。框架
from django.urls import path, include from .views import BookView, BookEditView, BookModelViewSet urlpatterns = [ # path('list', BookView.as_view()), # 查看全部的圖書 # 注意url中參數命名方式,2.0以前的寫法:'retrieve/(?P<id>\d+)' # 2.0以後的寫法:<>內聲明類型,冒號後面跟着關鍵字參數 # path('retrieve/<int:id>', BookEditView.as_view()) # 單條數據查看 path('list', BookModelViewSet.as_view({"get": "list", "post": "create"})), path('retrieve/<int:id>', BookModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})) ]
as_view方法自己是不支持傳參的,所以須要重寫該方法。ide
class ViewSetMixin(object): def as_view(self): """ 按照參數指定的去匹配 get-->list :return: """ pass class BookModelViewSet(ViewSetMixin, GenericAPIView, ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): pass
可是咱們不用本身去定義該方法,能夠直接使用框架已經提供好的ViewSetMixin:
from rest_framework.viewsets import ViewSetMixin
它作的主要事情就是重寫as_view方法:
class ViewSetMixin: @classonlymethod def as_view(cls, actions=None, **initkwargs): def view(request, *args, **kwargs): self = cls(**initkwargs) # We also store the mapping of request methods to actions, # so that we can later set the action attribute. # eg. `self.action = 'list'` on an incoming GET request. self.action_map = actions # Bind methods to actions # This is the bit that's different to a standard view # 這裏actions是前面url中提供的字典參數{"get": "list", "post": "create"} for method, action in actions.items(): # 循環獲得的method是get,action是list handler = getattr(self, action) # self是本身的視圖類 setattr(self, method, handler) # 在本身的視圖類中找list方法 if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs # And continue as usual # 作分發:get-->self.get;post-->self.post return self.dispatch(request, *args, **kwargs)
因爲self.get已經等於self.list,分發get對應的是list。
from rest_framework.viewsets import ViewSetMixin class BookModelViewSet(ViewSetMixin, GenericAPIView, ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): query_set = Book.objects.all() serializer_class = BookSerializer
因爲get去匹配時已經自動對應到了self.list方法。所以再也不自定義視圖方法。
from rest_framework.viewsets import ViewSetMixin class ModelViewSet(ViewSetMixin, GenericAPIView, ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): pass class BookModelViewSet(ModelViewSet): query_set = Book.objects.all() serializer_class = BookSerializer
class CreateModelMixin(object): """Create a model instance ==>建立一個實例""" def create(self, request, *args, **kwargs): # 獲取相關serializer serializer = self.get_serializer(data=request.data) # 進行serializer的驗證;raise_exception=True,一旦驗證不經過,再也不往下執行,直接引起異常 serializer.is_valid(raise_exception=True) # 調用perform_create()方法,保存實例 self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) def perform_create(self, serializer): # 保存實例 serializer.save() def get_success_headers(self, data): try: return {'Location': str(data[api_settings.URL_FIELD_NAME])} except (TypeError, KeyError): return {}
注意:
(1)perform_create( )對serializer直接進行save保存,當在一些情境下,須要對perform_create( )進行重寫。
(2)這個類的運行流程以下所示:
class ListModelMixin(object): """List a queryset.==> 列表頁獲取""" def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) # 這是一個分頁功能,若是在viewset中設置了pagination_class,那麼這裏就會起做用 # 獲取當前頁的queryset,若是不存在分頁,返回None page = self.paginate_queryset(queryset) if page is not None: # 分頁不爲空,那麼不能簡單的執行Response(serializer.data) # 還須要將相關的page信息序列化在進行響應 serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True) return Response(serializer.data)
ListModelMixin通常用來獲取列表頁,不須要重寫方法。
class RetrieveModelMixin(object): """ Retrieve a model instance.==> 獲取某一個對象的具體信息 """ def retrieve(self, request, *args, **kwargs): # 通常訪問的url都爲/obj/id/這種新式 # get_object()能夠獲取到這個id的對象 # 注意在viewset中設置lookup_field獲取重寫get_object()方法能夠指定id具體對象是什麼~! instance = self.get_object() serializer = self.get_serializer(instance) return Response(serializer.data)
class DestroyModelMixin(object): """ Destroy a model instance. """ def destroy(self, request, *args, **kwargs): instance = self.get_object() self.perform_destroy(instance) return Response(status=status.HTTP_204_NO_CONTENT) def perform_destroy(self, instance): instance.delete()
這一章簡要分析了源碼的內容以及各個mixins的邏輯,最重要的仍是學會重寫它們相關的方法。通常狀況下,當咱們在操做某一個model的時候,涉及到另一個model中數據的修改,那麼就須要對這個mixins下執行save的邏輯的方法進行重寫。
經過使用mixin類,使用更少的代碼重寫了這些視圖,但咱們還能夠再進一步。REST框架提供了一組已經混合好(mixed-in)的通用視圖,咱們可使用它來簡化咱們的views.py
模塊。
from rest_framework import mixins, generics class AuthorView(generics.ListCreateAPIView): queryset = Author.objects.all() # 配置queryset:告知這個類此次處理的數據 serializer_class = AuthorModelSerializers # 告知處理用到的序列化組件 class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView): queryset = Author.objects.all() # 配置queryset:告知這個類此次處理的數據 serializer_class = AuthorModelSerializers # 告知處理用到的序列化組件
class ListCreateAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView): """ Concrete view for listing a queryset or creating a model instance. """ def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs)
能夠看到源碼中將Mixins混合類和get\post函數都封裝進去了。
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, GenericAPIView): """ Concrete view for retrieving, updating or deleting a model instance. """ def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs) def patch(self, request, *args, **kwargs): return self.partial_update(request, *args, **kwargs) def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs)
其餘RetrieveDestroyAPIView、RetrieveUpdateAPIView、UpdateAPIView、DestroyAPIView等封裝方式徹底相似。
from django.contrib import admin from django.urls import path, re_path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), '''代碼省略''' # re_path(r'^authors/$', views.AuthorView.as_view(), name="author"), # re_path(r'^authors/(?P<pk>\d+)/$', views.AuthorDetailView.as_view(), name="detail_author"), # as_view參數指定什麼請求走什麼方法 re_path(r'^authors/$', views.AuthorViewSet.as_view({"get": "list", "post": "create"}), name="author_list"), re_path(r'^authors/(?P<pk>\d+)/$', views.AuthorViewSet.as_view({ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' }), name="author_detail"), ]
注意:
利用參數來指定什麼請求方式由哪個內部方法來執行。尤爲注意兩種不一樣get請求用不一樣的方法來處理。
from rest_framework import viewsets class AuthorViewSet(viewsets.ModelViewSet): queryset = Author.objects.all() # 配置queryset:告知這個類此次處理的數據 serializer_class = AuthorModelSerializers # 告知處理用到的序列化組件
class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): """ A viewset that provides default `create()`, `retrieve()`, `update()`, `partial_update()`, `destroy()` and `list()` actions. """ pass
ModelViewSet繼承了全部五個混合類。還繼承了GenericViewSet類。
class GenericViewSet(ViewSetMixin, generics.GenericAPIView): pass
能夠看到GenericViewSet繼承了前面學的generics.GenericAPIView類,這個類擴展了REST框架的APIView
類,可是它並無改寫dispatch方法,所以url中能夠添加參數與它無關。
GenericViewSet還繼承了ViewSetMixin類。
class ViewSetMixin(object): """ Overrides `.as_view()` so that it takes an `actions` keyword that performs the binding of HTTP methods to actions on the Resource. 覆蓋as_view方法須要接收一個actions參數來實現將HTTP方法綁定到資源。 For example, to create a concrete view binding the 'GET' and 'POST' methods to the 'list' and 'create' actions... 舉例來講,若是要建立一個具體視圖綁定'GET'和'POST'方法到'list'和'create'操做。可寫爲以下格式: view = MyViewSet.as_view({'get': 'list', 'post': 'create'}) """ @classonlymethod def as_view(cls, actions=None, **initkwargs): """ Because of the way class based views create a closure around the instantiated view, we need to totally reimplement `.as_view`, and slightly modify the view function that is created and returned. """ # actions must not be empty actions來接收{'get': 'list', 'post': 'create'} if not actions: # 爲空則報錯 raise TypeError("The `actions` argument must be provided when " "calling `.as_view()` on a ViewSet. For example " "`.as_view({'get': 'list'})`") # sanitize keyword arguments for key in initkwargs:..... # 這裏的值是空的 def view(request, *args, **kwargs):... return csrf_exempt(view) # 執行as_view 最終返回的仍是view函數
注意:
def foo(action=None, **kwargs): print(action) print(kwargs) foo({"a": 1}, b=2, c=3) """ {'a': 1} {'b': 2, 'c': 3} """ foo(a=2, b=3) """ None {'a': 2, 'b': 3} """ foo(**{"a": 1, "b": 3}) """ None {'a': 1, 'b': 3} """ foo({"a": 1, "b": 3}) """ {'a': 1, 'b': 3} {} """
因而可知as_view傳遞的參數{"get": "list", "post": "create"}是ViewSetMixin內改寫的as_view方法,由actions參數來接收的。
因爲acitons默認值是None,所以not None實際上是True,if not actions: 實際上是actions爲空則報錯的意思。
def view(request, *args, **kwargs): self = cls(**initkwargs) # We also store the mapping of request methods to actions, # so that we can later set the action attribute. # eg. `self.action = 'list'` on an incoming GET request. self.action_map = actions # 傳入的字典數據{'get': 'list', 'post': 'create'} # Bind methods to actions # This is the bit that's different to a standard view for method, action in actions.items(): # method:請求方式 action:實例方法 handler = getattr(self, action) # 反射獲得self.list self.create方法 setattr(self, method, handler) # 給請求方式設置對應的實例方法 if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs # And continue as usual return self.dispatch(request, *args, **kwargs)
在view函數中用self.action_map = actions 來接收傳入的字典數據{'get': 'list', 'post': 'create'}。
循環for method, action in actions.items(): 拿到method:請求方式和action:實例方法。
再經過反射方法:handler = getattr(self, action) 獲得self.list self.create方法。
最後經過反射方法setattr(self, method, handler) 給請求方式設置對應的實例方法:之後再找getattr(self, "get")的時候找到是self.list;找getattr(self, "post")的時候找到是self.create;
1. getattr()函數是Python自省的核心函數,具體使用大致以下: class A: def __init__(self): self.name = 'zhangjing' #self.age='24' def method(self): print"method print" Instance = A() print getattr(Instance , 'name, 'not find') #若是Instance 對象中有屬性name則打印self.name的值,不然打印'not find' print getattr(Instance , 'age', 'not find') #若是Instance 對象中有屬性age則打印self.age的值,不然打印'not find' print getattr(a, 'method', 'default') #若是有方法method,不然打印其地址,不然打印default print getattr(a, 'method', 'default')() #若是有方法method,運行函數並打印None不然打印default 2. hasattr(object, name) 說明:判斷對象object是否包含名爲name的特性(hasattr是經過調用getattr(ojbect, name)是否拋出異常來實現的) 3. setattr(object, name, value) 這是相對應的getattr()。參數是一個對象,一個字符串和一個任意值。字符串可能會列出一個現有的屬性或一個新的屬性。這個函數將值賦給屬性的。該對象容許它提供。例如,setattr(x,「foobar」,123)至關於x.foobar = 123。 4. delattr(object, name) 與setattr()相關的一組函數。參數是由一個對象(記住python中一切皆是對象)和一個字符串組成的。string參數必須是對象屬性名之一。該函數刪除該obj的一個由string指定的屬性。delattr(x, 'foobar')=del x.foobar
從ModelViewSet——》GenericViewSet——》GenericAPIView——》APIView一路回溯到APIView才找到dispatch方法。
def dispatch(self, request, *args, **kwargs): self.args = args self.kwargs = kwargs request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try: self.initial(request, *args, **kwargs) # Get the appropriate handler method if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) except Exception as exc: response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs) return self.response
當訪問是走的路由是re_path(r'^authors/$', views.AuthorViewSet.as_view({"get": "list", "post": "create"}), name="author_list"),get請求handler對應的是self.list。
而當訪問走的路由是re_path(r'^authors/(?P<pk>\d+)/$', views.AuthorViewSet.as_view({'get': 'retrieve',....
此時get請求handler對應的是self.retrieve。
如此就實現了兩個類合成一個類。
查看ModelViewSet源碼:
class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet):
在ListModelMixin找到list方法:
class ListModelMixin(object): """ List a queryset. """ def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True) return Response(serializer.data)
全部的視圖類在以下這四個文件內:
from rest_framework import views # APIView from rest_framework import generics # 公共通用視圖類:GenericAPIView,及各類組合視圖類CreateAPIView、ListAPIView、RetrieveAPIView等 from rest_framework import mixins # 混合繼承類:CreateModelMixin、ListModelMixin、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin from rest_framework import viewsets # 重寫as_view: ViewSetMixin;其餘類都是幫助去繼承ViewSetMixin
視圖類繼承順序,如Django REST Framework視圖圖譜所示:
首先 django是繼承 view的,DRF是從APIView開始繼承起,APIView封裝了request,其中包含了data、query_params等屬性、方法。
而後 GenericAPIView封裝了 get_queryset() 和 get_serializer();ViewSetMixin重寫了 as_view()方法。
隨後 GenericViewSet幫忙繼承GenericAPIView和ViewSetMixin。
最後最高層的封裝是 ModelViewSet。