檢視
REST framework 提供了眾多的通用檢視基類與擴充套件類,以簡化檢視的編寫。
APIView
rest_framework.views.APIView
APIView是REST framework提供的所有檢視的基類,繼承自Django的View父類。
GenericAPIView使用[通用檢視類]
繼承自APIVIew,主要增加了操作序列化器和資料庫查詢的方法,作用是為下面Mixin擴充套件類的執行提供方法支援。通常在使用時,可搭配一個或多個Mixin擴充套件類。
點選第一層檢視程式碼
class BookView(APIView):
renderer_classes = [JSONRenderer]
# 建立資料反序列化
def post(self, request):
ser = BookSerializers(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
# 讀取序列化
def get(self, request):
book_list = Books.objects.all()
# many=True 代表序列化多條資料
ser = BookSerializers(instance=book_list, many=True)
response = {'code': 100, 'msg': '查詢成功', 'result': ser.data}
return Response(response, status=status.HTTP_202_ACCEPTED, headers={'name': 'junjie'})
# 查詢單條
class BookDetailView(APIView):
def get(self, request, pk):
book = Books.objects.filter(pk=pk).first()
ser = BookSerializers(instance=book)
return Response(ser.data)
def delete(self, request, pk):
Books.objects.filter(pk=pk).delete()
return Response()
# 修改
def put(self, request, pk):
book = Books.objects.filter(pk=pk).first()
ser = BookSerializers(instance=book, data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
GenericAPIView[通用檢視類]的方法屬性以及方法,第二層的演變。
* 屬性
* serializer_class指明檢視使用的序列化器
* 方法
* get_serializer_class(self)
現在來想繼承GenericAPIView來寫檢視函式改如何寫?先檢視GenericAPIView類定義了什麼屬性和方法。
圖書的五個介面,第二層,精簡模型類和序列化類
from .models import Books, Publish
from rest_framework.generics import GenericAPIView
from .serizlizer import BookSerializers, PublishSerializers
from rest_framework.response import Response
class BookAPIView(GenericAPIView):
queryset = Books.objects.all()
serializer_class = BookSerializers
def get(self, request):
book_list = self.get_queryset()
ser = self.get_serializer(instance=book_list, many=True)
return Response(ser.data)
def post(self, request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
class BookDetailView(GenericAPIView):
queryset = Books.objects.all()
serializer_class = BookSerializers
def get(self, request, pk):
book_list = self.get_object()
ser = self.get_serializer(instance=book_list)
return Response(ser.data)
def put(self, request, pk):
book_obj = self.get_object()
# 得到序列化類物件,傳入單條物件和要修改的資料欄位
ser = self.get_serializer(instance=book_obj, data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
def delete(self, request, pk):
book = self.get_object()
book.delete()
return Response()
如果想要再寫一個檢視類只需要繼承GenericAPIView修改queryset和serializer_class即可,那麼有沒有別的方法可以節省程式碼?
使用GenericAPIView+5個檢視擴充套件類
from rest_framework.mixins import
CreateModelMixin, # 建立單個
ListModelMixin, # 查詢所有
DestroyModelMixin, # 刪除單個 碟嘶踹
UpdateModelMixin, # 新建單個
RetrieveModelMixin # 查詢單個 瑞吹霧
程式碼如下:
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, \
ListModelMixin
from rest_framework.generics import GenericAPIView
from .models import Books, Publish
from .serizlizer import BookSerializers, PublishSerializers
class BookAPIView(GenericAPIView,
# 建立資料
CreateModelMixin,
# 檢視所有
ListModelMixin):
queryset = Books.objects.all()
serializer_class = BookSerializers
def get(self, request):
print(request)
return self.list(request)
def post(self, request):
return self.create(request)
class BookDetailView(GenericAPIView,
UpdateModelMixin, # 修改單條資料
DestroyModelMixin, # 刪除單條
RetrieveModelMixin): # 查詢單條
queryset = Books.objects.all()
serializer_class = BookSerializers
def get(self, request, pk):
print(request)
return self.retrieve(request, pk)
def delete(self, request, pk):
print(request)
return self.destroy(request, pk)
def put(self, request, pk):
return self.update(request, pk)
為什麼叫檢視擴充套件類:因為他不是檢視類,檢視類必須是繼承View/APIView。
還有沒有辦法再精簡程式碼?
GenericAPIView的檢視子類,第三層
1)CreateAPIView
提供 post 方法
繼承自: GenericAPIView、CreateModelMixin
2)ListAPIView
提供 get 方法
繼承自:GenericAPIView、ListModelMixin
3)RetrieveAPIView
提供 get 方法
繼承自: GenericAPIView、RetrieveModelMixin
4)DestoryAPIView
提供 delete 方法
繼承自:GenericAPIView、DestoryModelMixin
5)UpdateAPIView
提供 put 和 patch 方法
繼承自:GenericAPIView、UpdateModelMixin
以及:
RetrieveAPIView, ListCreateAPIView, RetrieveUpdateDestroyAPIView, RetrieveUpdateAPIView, RetrieveDestroyAPIView
from rest_framework.generics import CreateAPIView, UpdateAPIView, DestroyAPIView, ListAPIView, RetrieveAPIView, \
ListCreateAPIView, RetrieveUpdateDestroyAPIView, RetrieveUpdateAPIView, RetrieveDestroyAPIView
class BookAPIView(ListCreateAPIView):
queryset = Books.objects.all()
serializer_class = BookSerializers
class BookDetailAPIView(RetrieveUpdateDestroyAPIView):
queryset = Books.objects.all()
serializer_class = BookSerializers
總結:
#兩個基類
APIView
GenericAPIView:有關資料庫操作,queryset 和serializer_class
#5個檢視擴充套件類(rest_framework.mixins)
CreateModelMixin:create方法建立一條
DestroyModelMixin:destory方法刪除一條
ListModelMixin:list方法獲取所有
RetrieveModelMixin:retrieve獲取一條
UpdateModelMixin:update修改一條
#9個子類檢視(rest_framework.generics)
CreateAPIView:繼承CreateModelMixin,GenericAPIView,有post方法,新增資料
DestroyAPIView:繼承DestroyModelMixin,GenericAPIView,有delete方法,刪除資料
ListAPIView:繼承ListModelMixin,GenericAPIView,有get方法獲取所有
UpdateAPIView:繼承UpdateModelMixin,GenericAPIView,有put和patch方法,修改資料
RetrieveAPIView:繼承RetrieveModelMixin,GenericAPIView,有get方法,獲取一條
ListCreateAPIView:繼承ListModelMixin,CreateModelMixin,GenericAPIView,有get獲取所有,post方法新增
RetrieveDestroyAPIView:繼承RetrieveModelMixin,DestroyModelMixin,GenericAPIView,有get方法獲取一條,delete方法刪除
RetrieveUpdateAPIView:繼承RetrieveModelMixin,UpdateModelMixin,GenericAPIView,有get獲取一條,put,patch修改
RetrieveUpdateDestroyAPIView:繼承RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView,有get獲取一條,put,patch修改,delete刪除
第五層,直接寫五個介面最終演示,自動生成路由。
from rest_framework.viewsets import ModelViewSet
# ModelViewSet繼承了5個檢視擴充套件類,GenericViewSet 和 ViewSetMixin
class BookAPIView(ModelViewSet):
queryset = Books.objects.all()
serializer_class = BookSerializers
繼承五個檢視擴充套件類的作用為用了五個介面方法。
GenericViewSet是什麼?
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
"""
The GenericViewSet class does not provide any actions by default,
but does include the base set of generic view behavior, such as
the `get_object` and `get_queryset` methods.
"""
pass
"""
已知:generics.GenericAPIView 中有View和APIView,以及四個方法
def get_queryset(self):
def get_object(self):
def get_serializer(self, *args, **kwargs):
def get_serializer_class(self):
"""
ViewSetMixin
class ViewSetMixin:
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
cls.name = None
cls.description = None
cls.suffix = None
cls.detail = None
cls.basename = None
# 註釋:
"""
此處與url相對應,actions是什麼?
path('books/', views.BookAPIView.as_view({'get':'list','post':'create'})),
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'})`")
# 註釋:
"""
字典.items()是將K,V拆出,此時method=K,action=V
以{'get':'list','post':'create'}舉例。
get = method,list = action
"""
for method, action in actions.items():
# 註釋:
"""
此時的self為檢視類物件BookAPIView
action是上述所講的url,as_view的第一個引數。
getattr反射,此時檢視類物件中沒有list,到父類ModelViewSet -->
mixins.ListModelMixin --> def list(self, request, *args, **kwargs):
handler 便是反射出來的list
setattr設定值,將list對映成get,檢視中的get方法實質上是list方法。
客戶端傳送get請求就能找到list
這裡主要用作區分使用者是查詢單條還是查詢所有
"""
handler = getattr(self, action)
setattr(self, method, handler)
self.request = request
self.args = args
self.kwargs = kwargs
# And continue as usual
return self.dispatch(request, *args, **kwargs)
# take name and docstring from class
update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
# We need to set these on the view function, so that breadcrumb
# generation can pick out these bits of information from a
# resolved URL.
view.cls = cls
view.initkwargs = initkwargs
view.actions = actions
return csrf_exempt(view)
第五層
匯入模組
from rest_framework.viewsets import ModelViewSet
直接寫五個介面最終演示,自動生成路由。
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet, GenericViewSet, ViewSet
# 直接寫五個介面,一定要繼承(ViewSetMixin),才能自動生成路由
# class BookAPIView(ModelViewSet):
# queryset = Books.objects.all()
# serializer_class = BookSerializers
# 查詢所有和查詢單個,如果只繼承了ReadOnlyModelViewSet,路由也需要更改。
# class BookAPIView(ReadOnlyModelViewSet):
# queryset = Books.objects.all()
# serializer_class = BookSerializers
# GenericViewSet:繼承了(ViewSetMixin, generics.GenericAPIView)
# ViewSet:繼承了(ViewSetMixin, views.APIView)
class BookAPIView(ViewSet):
def xjz(self, request):
return Response("junjie")
url
# 自動生成路由
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
# 必須繼承(ViewSetMixin),才能自動生成路由
router.register('books', views.BookAPIView)
urlpatterns = [
path('admin/', admin.site.urls),
# 將請求對映到對應的方法
path('books/', views.BookAPIView.as_view({'get':'list'})),
path('books/<int:pk>', views.BookAPIView.as_view({'get':'retrieve'})),
]
urlpatterns += router.urls
匯入模組
from rest_framework.routers import SimpleRouter
from django.urls import path,include
router = SimpleRouter()
# 必須繼承(ViewSetMixin),才能自動生成路由
router.register('admin', views.BookAPIView)
urlpatterns = [
# path('admin/', admin.site.urls),
path('api/',include(router.urls))
]
此時瀏覽器訪問admin的路由:http://127.0.0.1:8000/api/admin/