檢視元件,路由元件 Django Rest Framework 檢視和路由
檢視元件
-- 第一次封裝
-- GenericAPIView(APIView):
queryset = None
serializer_class = None
def get_queryset(self):
return self.queryset.all()
def get_serializer(self, *args, **kwargs):
return self.serializer_class(*args, **kwargs)
-- class ListModelMixin(object):
def list(...):
pass
-- 各個檢視方法封裝成類
-- 檢視
class BookView(GenericAPIView, ListModelMixin):
def get(self, request):
return self.list(request)
-- 第二次封裝
-- 方便繼承
-- 第三次封裝
-- ViewSetMixin 重寫as_vieb w方法
在執行self.dispatch()方法之前
把self.get = self.list
-- 在ViewSetMixin後 路由才可以傳參
路由元件
-- 匯入
from rest_framwork.routers import DefaultRouter
-- 例項化物件
router = DefaultRouter()
-- 註冊
router.register(路由,檢視)
-- urlpatterns += router.urls
-- 生成的路由都是帶引數的 你的檢視類必須支援路由傳參
程式碼..
from rest_framework.routers import DefaultRouter # 幫助我們生成帶引數的路由
router=DefaultRouter() #例項化DsfaultRouter
router.register('^book',views.BokModelView) # 註冊我們的路由以及檢視
urlpatterns += router.urls
DRF的檢視
APIView
我們django中寫CBV的時候繼承的是View,rest_framework繼承的是APIView,那麼他們兩個有什麼不同呢~~~
?
urlpatterns
=
[
url(r
'^book$'
, BookView.as_view()),
url(r
'^book/(?P<id>\d+)$'
, BookEditView.as_view()),
]
|
我們可以看到,不管是View還是APIView最開始呼叫的都是as_view()方法~~那我們走進原始碼看看~~
我們能看到,APIView繼承了View, 並且執行了View中的as_view()方法,最後把view返回了,用csrf_exempt()方法包裹後去掉了csrf的認證。
那我們看看View中的as_view()方法做了什麼~
我們看到了~在View中的as_view方法返回了view函式,而view函式執行了self.dispatch()方法~~但是這裡的dispatch方法應該是我們APIView中的~~
我們去initialize_request中看下把什麼賦值給了request,並且賦值給了self.request, 也就是我們在檢視中用的request.xxx到底是什麼~~
我們看到,這個方法返回的是Request這個類的例項物件~~我們注意我們看下這個Request類中的第一個引數request,是我們走我們django的時候的原來的request~
我們看到了,這個Request類把原來的request賦值給了self._request, 也就是說以後_request是我們老的request,新的request是我們這個Request類~~
那我們繼承APIView之後請求來的資料都在哪呢~~
我們用了rest_framework框架以後,我們的request是重新封裝的Request類~
request.query_params 存放的是我們get請求的引數
request.data 存放的是我們所有的資料,包括post請求的以及put,patch請求~~~
相比原來的django的request,我們現在的request更加精簡,清晰了~~~
現在我們知道了APIView和View的一些區別~~當然還有~~後面我們還會說~~
我們寫的檢視可能對多個表進行增刪改查,就導致我們的檢視特別多重複的程式碼~~
那麼我們嘗試著來進行封裝一下~~
第一次封裝
class BookView(APIView): def get(self, request): query_set = Book.objects.all() book_ser = BookSerializer(query_set, many=True) return Response(book_ser.data) def post(self, request): query_set = request.data book_ser = BookSerializer(data=query_set) if book_ser.is_valid(): book_ser.save() return Response(book_ser.validated_data) else: return Response(book_ser.errors) class BookEditView(APIView): def get(self, request, id): query_set = Book.objects.filter(id=id).first() book_ser = BookSerializer(query_set) return Response(book_ser.data) def patch(self, request, id): query_set = Book.objects.filter(id=id).first() book_ser = BookSerializer(query_set, data=request.data, partial=True) if book_ser.is_valid(): book_ser.save() return Response(book_ser.validated_data) else: return Response(book_ser.errors) def delete(self, request, id): query_set = Book.objects.filter(id=id).first() if query_set: query_set.delete() return Response("") else: return Response("刪除的書籍不存在")APIView檢視
class GenericAPIView(APIView): queryset = None serializer_class = None def get_queryset(self): return self.queryset.all() def get_serializer(self, *args, **kwargs): return self.serializer_class(*args, **kwargs) class ListModelMixin(object): def list(self, request, *args, **kwargs): queryset = self.get_queryset() serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) class CreateModelMixin(object): def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.validated_data) else: return Response(serializer.errors) class RetrieveModelMixin(object): def retrieve(self, request, id, *args, **kwargs): book_obj = self.get_queryset().filter(pk=id).first() book_ser = self.get_serializer(book_obj) return Response(book_ser.data) class UpdateModelMixin(object): def update(self, request, id, *args, **kwargs): book_obj = self.get_queryset().filter(pk=id).first() book_ser = self.get_serializer(book_obj, data=request.data, partial=True) if book_ser.is_valid(): book_ser.save() return Response(book_ser.validated_data) else: return Response(book_ser.errors) class DestroyModelMixin(object): def destroy(self, request, id, *args, **kwargs): queryset = self.get_queryset() try: queryset.get(pk=id).delete() return Response("") except Exception as e: return Response("資訊有誤") # 我們把公共的部分抽出來 這樣不管寫多少表的增刪改查都變的很簡單 # 這樣封裝後我們的檢視會變成這樣 class BookView(GenericAPIView, ListModelMixin, CreateModelMixin): queryset = Book.objects.all() serializer_class = BookSerializer 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 BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): queryset = Book.objects.all() serializer_class = BookSerializer def get(self, request, id, *args, **kwargs): return self.retrieve(request, id, *args, **kwargs) def patch(self, request, id, *args, **kwargs): return self.update(request, id, *args, **kwargs) def destroy(self, request, id, *args, **kwargs): return self.delete(request, id, *args, **kwargs)第一次封裝
我們封裝的GenericAPIView,包括封裝每個方法的類,其實框架都幫我們封裝好了~~
我們可以直接繼承這些類~~來實現上面的檢視~~可是還有沒有更簡單的方法呢~我們再次封裝一下~~
第二次封裝
# 上面我們寫的繼承類太長了~~我們再改改 class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin): pass class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): pass class BookView(ListCreateAPIView): queryset = Book.objects.all() serializer_class = BookSerializer 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 BookEditView(RetrieveUpdateDestroyAPIView): queryset = Book.objects.all() serializer_class = BookSerializer def get(self, request, id, *args, **kwargs): return self.retrieve(request, id, *args, **kwargs) def patch(self, request, id, *args, **kwargs): return self.update(request, id, *args, **kwargs) def delete(self, request, id, *args, **kwargs): return self.delete(request, id, *args, **kwargs)第二次封裝
這次我們只是讓繼承變的簡單了一點而已,好像並沒有什麼大的進步~~
我們可不可以把這兩個檢視合併成一個檢視呢~~~框架給我們提供了一個路由傳參的方法~~
我們看下ViewSetMixin
actions這個預設引數其實就是我們路由可以進行傳參了~~~
下面這個迴圈~可以看出~我們要傳的引數是一個欄位~key應該是我們的請求方式,value應該對應我們處理的方法~
這樣我們每個檢視就不用在寫函數了~因為已經和內部實現的函式相對應了~
第三次封裝
urlpatterns = [ # url(r'^book$', BookView.as_view()), # url(r'^book/(?P<id>\d+)$', BookEditView.as_view()), url(r'^book$', BookView.as_view({"get": "list", "post": "create"})), url(r'^book/(?P<pk>\d+)$', BookView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})), ]路由urls.py
from rest_framework.viewsets import ViewSetMixin # class BookView(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView): # queryset = Book.objects.all() # serializer_class = BookSerializer # 如果我們再定義一個類 class ModelViewSet(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView): pass class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer第三次封裝
我們現在的檢視就只要寫兩行就可以了~~~
其實我們寫的所有的檢視~框架都幫我們封裝好了~
注意一點~~用框架封裝的檢視~我們url上的那個關鍵字引數要用pk~~系統預設的~~
奉獻一張圖來看下我們的繼承順序~~~
DRF的路由
我們上面的路由傳參寫的特別多~~框架也幫我們封裝好了~
from .views import BookView from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register(r"book", BookView) urlpatterns = [ # url(r'^book$', BookView.as_view()), # url(r'^book/(?P<id>\d+)$', BookEditView.as_view()), # url(r'^book$', BookView.as_view({"get": "list", "post": "create"})), # url(r'^book/(?P<pk>\d+)$', BookView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})), ] urlpatterns += router.urls路由
我們可以看到~~通過框架我們可以把路由檢視都變的非常簡單~~
但是需要自定製的時候還是需要我們自己用APIView寫~~當不需要那麼多路由的時候~也不要用這種路由註冊~~
總之~~一切按照業務需要去用~~~
DRF的檢視
APIView
我們django中寫CBV的時候繼承的是View,rest_framework繼承的是APIView,那麼他們兩個有什麼不同呢~~~
?
urlpatterns
=
[
url(r
'^book$'
, BookView.as_view()),
url(r
'^book/(?P<id>\d+)$'
, BookEditView.as_view()),
]
|
我們可以看到,不管是View還是APIView最開始呼叫的都是as_view()方法~~那我們走進原始碼看看~~
我們能看到,APIView繼承了View, 並且執行了View中的as_view()方法,最後把view返回了,用csrf_exempt()方法包裹後去掉了csrf的認證。
那我們看看View中的as_view()方法做了什麼~
我們看到了~在View中的as_view方法返回了view函式,而view函式執行了self.dispatch()方法~~但是這裡的dispatch方法應該是我們APIView中的~~
我們去initialize_request中看下把什麼賦值給了request,並且賦值給了self.request, 也就是我們在檢視中用的request.xxx到底是什麼~~
我們看到,這個方法返回的是Request這個類的例項物件~~我們注意我們看下這個Request類中的第一個引數request,是我們走我們django的時候的原來的request~
我們看到了,這個Request類把原來的request賦值給了self._request, 也就是說以後_request是我們老的request,新的request是我們這個Request類~~
那我們繼承APIView之後請求來的資料都在哪呢~~
我們用了rest_framework框架以後,我們的request是重新封裝的Request類~
request.query_params 存放的是我們get請求的引數
request.data 存放的是我們所有的資料,包括post請求的以及put,patch請求~~~
相比原來的django的request,我們現在的request更加精簡,清晰了~~~
現在我們知道了APIView和View的一些區別~~當然還有~~後面我們還會說~~
我們寫的檢視可能對多個表進行增刪改查,就導致我們的檢視特別多重複的程式碼~~
那麼我們嘗試著來進行封裝一下~~
第一次封裝
class BookView(APIView): def get(self, request): query_set = Book.objects.all() book_ser = BookSerializer(query_set, many=True) return Response(book_ser.data) def post(self, request): query_set = request.data book_ser = BookSerializer(data=query_set) if book_ser.is_valid(): book_ser.save() return Response(book_ser.validated_data) else: return Response(book_ser.errors) class BookEditView(APIView): def get(self, request, id): query_set = Book.objects.filter(id=id).first() book_ser = BookSerializer(query_set) return Response(book_ser.data) def patch(self, request, id): query_set = Book.objects.filter(id=id).first() book_ser = BookSerializer(query_set, data=request.data, partial=True) if book_ser.is_valid(): book_ser.save() return Response(book_ser.validated_data) else: return Response(book_ser.errors) def delete(self, request, id): query_set = Book.objects.filter(id=id).first() if query_set: query_set.delete() return Response("") else: return Response("刪除的書籍不存在")APIView檢視
class GenericAPIView(APIView): queryset = None serializer_class = None def get_queryset(self): return self.queryset.all() def get_serializer(self, *args, **kwargs): return self.serializer_class(*args, **kwargs) class ListModelMixin(object): def list(self, request, *args, **kwargs): queryset = self.get_queryset() serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) class CreateModelMixin(object): def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.validated_data) else: return Response(serializer.errors) class RetrieveModelMixin(object): def retrieve(self, request, id, *args, **kwargs): book_obj = self.get_queryset().filter(pk=id).first() book_ser = self.get_serializer(book_obj) return Response(book_ser.data) class UpdateModelMixin(object): def update(self, request, id, *args, **kwargs): book_obj = self.get_queryset().filter(pk=id).first() book_ser = self.get_serializer(book_obj, data=request.data, partial=True) if book_ser.is_valid(): book_ser.save() return Response(book_ser.validated_data) else: return Response(book_ser.errors) class DestroyModelMixin(object): def destroy(self, request, id, *args, **kwargs): queryset = self.get_queryset() try: queryset.get(pk=id).delete() return Response("") except Exception as e: return Response("資訊有誤") # 我們把公共的部分抽出來 這樣不管寫多少表的增刪改查都變的很簡單 # 這樣封裝後我們的檢視會變成這樣 class BookView(GenericAPIView, ListModelMixin, CreateModelMixin): queryset = Book.objects.all() serializer_class = BookSerializer 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 BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): queryset = Book.objects.all() serializer_class = BookSerializer def get(self, request, id, *args, **kwargs): return self.retrieve(request, id, *args, **kwargs) def patch(self, request, id, *args, **kwargs): return self.update(request, id, *args, **kwargs) def destroy(self, request, id, *args, **kwargs): return self.delete(request, id, *args, **kwargs)第一次封裝
我們封裝的GenericAPIView,包括封裝每個方法的類,其實框架都幫我們封裝好了~~
我們可以直接繼承這些類~~來實現上面的檢視~~可是還有沒有更簡單的方法呢~我們再次封裝一下~~
第二次封裝
# 上面我們寫的繼承類太長了~~我們再改改 class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin): pass class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): pass class BookView(ListCreateAPIView): queryset = Book.objects.all() serializer_class = BookSerializer 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 BookEditView(RetrieveUpdateDestroyAPIView): queryset = Book.objects.all() serializer_class = BookSerializer def get(self, request, id, *args, **kwargs): return self.retrieve(request, id, *args, **kwargs) def patch(self, request, id, *args, **kwargs): return self.update(request, id, *args, **kwargs) def delete(self, request, id, *args, **kwargs): return self.delete(request, id, *args, **kwargs)第二次封裝
這次我們只是讓繼承變的簡單了一點而已,好像並沒有什麼大的進步~~
我們可不可以把這兩個檢視合併成一個檢視呢~~~框架給我們提供了一個路由傳參的方法~~
我們看下ViewSetMixin
actions這個預設引數其實就是我們路由可以進行傳參了~~~
下面這個迴圈~可以看出~我們要傳的引數是一個欄位~key應該是我們的請求方式,value應該對應我們處理的方法~
這樣我們每個檢視就不用在寫函數了~因為已經和內部實現的函式相對應了~
第三次封裝
urlpatterns = [ # url(r'^book$', BookView.as_view()), # url(r'^book/(?P<id>\d+)$', BookEditView.as_view()), url(r'^book$', BookView.as_view({"get": "list", "post": "create"})), url(r'^book/(?P<pk>\d+)$', BookView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})), ]路由urls.py
from rest_framework.viewsets import ViewSetMixin # class BookView(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView): # queryset = Book.objects.all() # serializer_class = BookSerializer # 如果我們再定義一個類 class ModelViewSet(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView): pass class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer第三次封裝
我們現在的檢視就只要寫兩行就可以了~~~
其實我們寫的所有的檢視~框架都幫我們封裝好了~
注意一點~~用框架封裝的檢視~我們url上的那個關鍵字引數要用pk~~系統預設的~~
奉獻一張圖來看下我們的繼承順序~~~
DRF的路由
我們上面的路由傳參寫的特別多~~框架也幫我們封裝好了~
from .views import BookView from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register(r"book", BookView) urlpatterns = [ # url(r'^book$', BookView.as_view()), # url(r'^book/(?P<id>\d+)$', BookEditView.as_view()), # url(r'^book$', BookView.as_view({"get": "list", "post": "create"})), # url(r'^book/(?P<pk>\d+)$', BookView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})), ] urlpatterns += router.urls路由
我們可以看到~~通過框架我們可以把路由檢視都變的非常簡單~~
但是需要自定製的時候還是需要我們自己用APIView寫~~當不需要那麼多路由的時候~也不要用這種路由註冊~~
總之~~一切按照業務需要去用~~~