DRF 檢視元件
DRF框架提供了很多通用的檢視基類與擴充套件類,上篇使用的APIView是比較偏Base的,檢視的使用更加簡化了程式碼,這裡介紹一下其他檢視的用法
Django REST framwork 提供的檢視的主要作用:
- 控制序列化器的執行(檢驗、儲存、轉換資料)
- 控制資料庫查詢的執行
先來看看這其中的人情世故:兩個檢視基本類,五個擴充套件類,九個檢視子類,檢視集方法,檢視集··
檢視元件大綱
兩個檢視基本類
匯入:
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
- APIView:DRF最頂層檢視類
- GenericAPIView:DRF通用檢視類
五個擴充套件類
擴充套件類不是檢視類,沒有整合APIView,需要配合GenericAPIView使用,因為五個擴充套件類的實現需要呼叫GenericAPIView提供的序列化器與資料庫查詢的方法
主要是用來對資料進行增刪改查
匯入
from rest_framework.mixins import CreateModelMixin,ListModelMixin,DestroyModelMixin,RetrieveModelMixin,UpdateModelMixin
- CreateModelMixin
- ListModelMixin
- DestroyModelMixin
- RetrieveModelMixin
- UpdateModelMixin
九個子類檢視
匯入
from rest_framework.generics import CreateAPIView,ListAPIView,DestroyAPIView,RetrieveAPIView,UpdateAPIView,ListCreateAPIView,RetrieveUpdateAPIView,RetrieveUpdateDestroyAPIView,RetrieveDestroyAPIView
檢視子類其實可以理解為GenericAPIView通用檢視類和Mixin擴充套件類的排列組合組成的,底層事通過封裝和繼承來寫
-
CreateAPIView
提供 post 方法 繼承自: GenericAPIView、CreateModelMixin
-
ListAPIView
提供 get 方法 繼承自:GenericAPIView、ListModelMixin
-
DestroyAPIView
提供 delete 方法 繼承自:GenericAPIView、DestoryModelMixin
-
RetrieveAPIView
提供 get 方法 繼承自: GenericAPIView、RetrieveModelMixin
-
UpdateAPIView
提供 put 和 patch 方法 繼承自:GenericAPIView、UpdateModelMixin
-
ListCreateAPIView
提供get 和 post方法 繼承自:ListModelMixin、CreateModelMixin、GenericAPIView
-
RetrieveUpdateAPIView
提供 get、put、patch方法 繼承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
-
RetrieveDestroyAPIView
提供:get、delete方法 繼承自:RetrieveModelMixin、DestroyModelMixin、GenericAPIView
-
RetrieveUpdateDestroyAPIView
提供 get、put、patch、delete方法 繼承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
檢視集
匯入
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet,ViewSet,GenericViewSet,ViewSetMixin
常用檢視集父類
-
ModelViewSet:繼承自GenericViewSet,同時包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
-
ReadOnlyModelViewSet:繼承自GenericViewSet,同時包括了ListModelMixin、RetrieveModelMixin。
-
ViewSet:繼承自APIView與ViewSetMixin,作用也與APIView基本類似,提供了身份認證、許可權校驗、流量管理等。ViewSet主要通過繼承ViewSetMixin來實現在呼叫as_view()時傳入字典({
'get'
:'list'
})的對映處理工作。- 在ViewSet中,沒有提供任何動作action方法,需要我們自己實現action方法。
-
GenericViewSet:使用ViewSet通常並不方便,因為
list
、retrieve、create、update、destory等方法都需要自己編寫,而這些方法與前面講過的Mixin擴充套件類提供的方法同名,所以我們可以通過繼承Mixin擴充套件類來複用這些方法而無需自己編寫。但是Mixin擴充套件類依賴與GenericAPIView,所以還需要繼承GenericAPIView。- GenericViewSet就幫助我們完成了這樣的繼承工作,繼承自GenericAPIView與
ViewSetMixin,在實現了呼叫as_view()時傳入字典(如
{'get'
:'list'
}`)的對映處理工作的同時,還提供了GenericAPIView提供的基礎方法,可以直接搭配Mixin擴充套件類使用。
- GenericViewSet就幫助我們完成了這樣的繼承工作,繼承自GenericAPIView與
魔法類
- ViewSetMixin:控制自動生成路由
一覽表
DRF中檢視的“七十二變”
第一層是繼承APIView寫,第二層基於基於GenericAPIView寫,第三層基於GenericAPIView+五個擴充套件類寫,第四層通過九個檢視子類來寫,第五層是通過ViewSet寫
ps:第幾層是我意淫出來的詞不要介意~,一層更比一層牛,欲練此功必先自宮!!!
第一層:基於APIview的五個介面
class BookView(APIView):
def get(self, requets):
# 序列化
book_list = models.Book.objects.all()
# 序列化多條資料many=True
ser = serializer.BookSerializer(instance=book_list, many=True)
return Response(ser.data)
def post(self, request):
# 獲取反序列化資料
ser = serializer.BookSerializer(data=request.data)
if ser.is_valid():
# 校驗通過存入資料庫,不需要重寫create方法了
ser.save()
return Response({'code': 100, 'msg': '新增成功', 'data': ser.data})
# 校驗失敗
return Response({'code': 101, 'msg': '校驗未通過', 'error': ser.errors})
class BookViewDetail(APIView):
def get(self, request, pk):
book = models.Book.objects.filter(pk=pk).first()
ser = serializer.BookSerializer(instance=book)
return Response(ser.data)
def put(self, request, pk):
book = models.Book.objects.filter(pk=pk).first()
# 修改,instance和data都要傳
ser = serializer.BookSerializer(instance=book, data=request.data)
if ser.is_valid():
# 校驗通過修改,不需要重寫update
ser.save()
return Response({'code:': 100, 'msg': '修改成功', 'data': ser.data})
# 校驗不通過
return Response({'code:': 102, 'msg': '校驗未通過,修改失敗', 'error': ser.errors})
def delete(self, request, pk):
models.Book.objects.filter(pk=pk).delete()
return Response({'code': 100, 'msg': '刪除成功'})
第一層五個介面demo
ModelSerializer序列化器實戰 - HammerZe - 部落格園 (cnblogs.com)
第二層:基於GenericAPIView的五個介面
常用類屬性:
-GenericAPIView 繼承了APIView,封裝了一些屬性和方法,跟資料庫打交道
-queryset = None # 指定序列化集
-serializer_class = None # 指定序列化類
-lookup_field = 'pk' # 查詢單條,分組分出來的引數,轉換器物件引數的名字
-filter_backends # 過濾排序功能會用它
-pagination_class # 分頁功能
-get_queryset() # 獲取要序列化的資料,後期可能會重寫
-get_object() # 通過lookup_field查詢的
-get_serializer() # 使用它序列化
-get_serializer_class() # 返回序列化類 ,後期可能重寫
demo:
# 指定序列化集
queryset = models.Book.objects.all()
# 指定序列化類
serializer_class = serializer.BookSerializer
第二層五個介面demo
from rest_framework.response import Response
from app01 import models
from app01 import serializer
from rest_framework.generics import GenericAPIView
# 書檢視類
class BookView(GenericAPIView):
# 指定序列化集
queryset = models.Book.objects.all()
# 指定序列化類
serializer_class = serializer.BookSerializer
def get(self, requets):
# obj = self.queryset()
obj = self.get_queryset() # 等同於上面
# ser = self.get_serializer_class()(instance=obj,many=True)
ser = self.get_serializer(instance=obj,many=True) # 等同於上面
return Response(ser.data)
def post(self, request):
# 獲取反序列化資料
# ser = serializer.BookSerializer(data=request.data)
ser = self.get_serializer(data = request.data)
if ser.is_valid():
# 校驗通過存入資料庫,不需要重寫create方法了
ser.save()
return Response({'code': 100, 'msg': '新增成功', 'data': ser.data})
# 校驗失敗
return Response({'code': 101, 'msg': '校驗未通過', 'error': ser.errors})
class BookViewDetail(GenericAPIView):
# 指定序列化集
queryset = models.Book.objects.all()
# 指定序列化類
serializer_class = serializer.BookSerializer
def get(self, request, pk):
# book = models.Book.objects.filter(pk=pk).first()
book = self.get_object() # 根據pk拿到單個物件
# ser = serializer.BookSerializer(instance=book)
ser = self.get_serializer(instance=book)
return Response(ser.data)
def put(self, request, pk):
# book = models.Book.objects.filter(pk=pk).first()
book = self.get_object()
# 修改,instance和data都要傳
# ser = serializer.BookSerializer(instance=book, data=request.data)
ser = self.get_serializer(instance=book,data=request.data)
if ser.is_valid():
# 校驗通過修改,不需要重寫update
ser.save()
return Response({'code:': 100, 'msg': '修改成功', 'data': ser.data})
# 校驗不通過
return Response({'code:': 102, 'msg': '校驗未通過,修改失敗', 'error': ser.errors})
def delete(self, request, pk):
# models.Book.objects.filter(pk=pk).delete()
self.get_object().delete()
return Response({'code': 100, 'msg': '刪除成功'})
路由
path('books/', views.BookView.as_view()),
path('books/<int:pk>', views.BookViewDetail.as_view())
總結:到第二層只需修改queryset
和serializer_class
類屬性即可,其餘都不需要修改
注意:雖然pk沒有在orm語句中過濾使用,但是路由分組要用,所以不能刪,或者寫成*args **kwargs
接收多餘的引數,且路由轉換器必須寫成pk
# 原始碼
lookup_field = 'pk'
lookup_url_kwarg = None
get_queryset()
方法可以重寫,如果我們需要在一個檢視類內操作另外表模型,來指定序列化的資料
class BookViewDetail(GenericAPIView):
queryset = models.Book.objects.all()
···
'''
指定序列化資料的格式:
self.queryset()
self.get_queryset() # 等同於上面
queryset = models.Book.objects.all()
'''
# 可以重寫get_queryset方法在book檢視類裡操作作者模型
def get_queryset(self,request):
if self.request.path == '/user'
return Author.objects.all()
···
# 這樣序列化的資料就不一樣了,根據不同的條件序列化不同的資料
'''當然還可以通過重寫get_serializer_class來返回其他序列化器類'''
第三層:基於GenericAPIView+五個檢視擴充套件類寫
五個檢視擴充套件類:from rest_framework.mixins import CreateModelMixin,ListModelMixin,DestroyModelMixin,RetrieveModelMixin,UpdateModelMixin
通過GenericAPIView+檢視擴充套件類來使得程式碼更簡單,一個介面對應一個擴充套件類,注意擴充套件類不是檢視類
- ListModelMixin:獲取所有API,對應list()方法
- CreateModelMixin:新增一條API,對應create()方法
- UpdateModelMixin:修改一條API,對應update()方法
- RetrieveModelMixin:獲取一條API,對應retrieve()方法
- DestroyModelMixin:刪除一條API,對應destroy()方法
注意:CreateModelMixin擴充套件類提供了更高階的方法,可以通過重寫來校驗資料存入
def perform_create(self, serializer):
serializer.save()
第三層五個介面demo
from app01 import models
from app01 import serializer
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import CreateModelMixin,ListModelMixin,DestroyModelMixin,RetrieveModelMixin,UpdateModelMixin
# 獲取所有和新增API
class BookView(ListModelMixin,CreateModelMixin,GenericAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
def get(self, request):
return super().list(request)
def post(self, request):
return super().create(request)
# 獲取刪除修改單個API
class BookViewDetail(UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin,GenericAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
def get(self, request, *args,**kwargs):
return super().retrieve(request, *args,**kwargs)
def put(self, request, *args,**kwargs):
return super().update(request, *args,**kwargs)
def delete(self, request, *args,**kwargs):
return super().destroy(request, *args,**kwargs)
總結
通過進一次封裝+繼承程式碼也變得越來越少了
GenericAPIView速寫五個介面demo
模型
from django.db import models
# Create your models here.
# build four model tables
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.DecimalField(decimal_places=2, max_digits=5)
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
def __str__(self):
return self.name
# 自定製欄位
@property
def publish_detail(self):
return {'name': self.publish.name, 'addr': self.publish.city}
@property
def author_list(self):
l = []
print(self.authors.all()) # <QuerySet [<Author: Author object (1)>, <Author: Author object (2)>]>
for author in self.authors.all():
print(author.author_detail) # AuthorDetail object (1)
l.append({'name': author.name, 'age': author.age, 'addr': author.author_detail.addr})
return l
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
def __str__(self):
return self.name
@property
def authordetail_info(self):
return {'phone':self.author_detail.telephone,'addr':self.author_detail.addr}
class AuthorDetail(models.Model):
telephone = models.BigIntegerField()
addr = models.CharField(max_length=64)
class Publish(models.Model):
name = models.CharField(max_length=32)
city = models.CharField(max_length=32)
email = models.EmailField()
序列化器
from django.db import models
# Create your models here.
# build four model tables
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.DecimalField(decimal_places=2, max_digits=5)
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
def __str__(self):
return self.name
# 自定製欄位
@property
def publish_detail(self):
return {'name': self.publish.name, 'addr': self.publish.city}
@property
def author_list(self):
l = []
print(self.authors.all()) # <QuerySet [<Author: Author object (1)>, <Author: Author object (2)>]>
for author in self.authors.all():
print(author.author_detail) # AuthorDetail object (1)
l.append({'name': author.name, 'age': author.age, 'addr': author.author_detail.addr})
return l
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
def __str__(self):
return self.name
@property
def authordetail_info(self):
return {'phone':self.author_detail.telephone,'addr':self.author_detail.addr}
class AuthorDetail(models.Model):
telephone = models.BigIntegerField()
addr = models.CharField(max_length=64)
class Publish(models.Model):
name = models.CharField(max_length=32)
city = models.CharField(max_length=32)
email = models.EmailField()
檢視
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin, DestroyModelMixin, RetrieveModelMixin, \
UpdateModelMixin
from app01 import models
from app01 import serializer
# 書檢視類
class BookView(ListModelMixin, CreateModelMixin, GenericAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
def get(self, request):
return super().list(request)
def post(self, request):
return super().create(request)
class BookViewDetail(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
def get(self, request, *args, **kwargs):
return super().retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return super().update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return super().destroy(request, *args, **kwargs)
# 作者
class AuthorView(ListModelMixin, CreateModelMixin, GenericAPIView):
queryset = models.Author.objects.all()
serializer_class = serializer.AuthorSerializer
def get(self, request):
return super().list(request)
def post(self, request):
return super().create(request)
class AuthorViewDetail(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView):
queryset = models.Author.objects.all()
serializer_class = serializer.AuthorSerializer
def get(self, request, *args, **kwargs):
return super().retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return super().update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return super().destroy(request, *args, **kwargs)
# 作者詳情
class AuthorDetailView(ListModelMixin, CreateModelMixin, GenericAPIView):
queryset = models.AuthorDetail.objects.all()
serializer_class = serializer.AuthorDetailSerializer
def get(self, request):
return super().list(request)
def post(self, request):
return super().create(request)
class OneAuthorViewDetail(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView):
queryset = models.AuthorDetail.objects.all()
serializer_class = serializer.AuthorDetailSerializer
def get(self, request, *args, **kwargs):
return super().retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return super().update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return super().destroy(request, *args, **kwargs)
# 出版社
class PublishView(ListModelMixin, CreateModelMixin, GenericAPIView):
queryset = models.Publish.objects.all()
serializer_class = serializer.PublishSerializer
def get(self, request):
return super().list(request)
def post(self, request):
return super().create(request)
class PublishViewDetail(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView):
queryset = models.Publish.objects.all()
serializer_class = serializer.PublishSerializer
def get(self, request, *args, **kwargs):
return super().retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return super().update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return super().destroy(request, *args, **kwargs)
路由
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
# 書
path('books/', views.BookView.as_view()),
path('books/<int:pk>', views.BookViewDetail.as_view()),
# 作者
path('authors/', views.AuthorView.as_view()),
path('authors/<int:pk>', views.AuthorViewDetail.as_view()),
# 作者詳情
path('authorsdetail/', views.AuthorDetailView.as_view()),
path('authorsdetail/<int:pk>', views.OneAuthorViewDetail.as_view()),
# 出版社
path('publish/', views.PublishView.as_view()),
path('publish/<int:pk>', views.PublishViewDetail.as_view()),
]
Postman以及測完,請放心使用~
第四層:GenericAPIView+九個檢視子類寫五個介面
匯入檢視子類:from rest_framework.generics import CreateAPIView,ListAPIView,DestroyAPIView,RetrieveAPIView,UpdateAPIView,ListCreateAPIView,RetrieveUpdateAPIView,RetrieveUpdateDestroyAPIView,RetrieveDestroyAPIView
使用哪個繼承哪個就可以了,具體可以看繼承的父類裡有什麼方法不需要刻意去記
from rest_framework.generics import CreateAPIView,ListAPIView,DestroyAPIView,RetrieveAPIView,UpdateAPIView,ListCreateAPIView,RetrieveUpdateAPIView,RetrieveUpdateDestroyAPIView,RetrieveDestroyAPIView
# 1、查詢所有,新增API
class BookView(ListCreateAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
# 2、新增介面
class BookView(CreateAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
# 3、查詢介面
class BookView(ListAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
# 4、查詢單個,修改一個,刪除一個介面
class BookViewDetail(RetrieveUpdateDestroyAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
# 5、查詢單個介面
class BookViewDetail(RetrieveAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
# 6、修改單個介面
class BookViewDetail(UpdateAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
# 7、刪除單個介面
class BookViewDetail(DestroyAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
# 8、查詢單個、修改介面
class BookViewDetail(RetrieveUpdateAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
# 9、查詢單個、刪除介面
class BookViewDetail(RetrieveDestroyAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
'''上述共九個檢視子類,九九歸一劍訣~'''
# 更新和刪除介面自己整合
class BookViewDetail(UpdateAPIView,DestroyAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
第四層快速寫五個介面demo
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
from app01 import models
from app01 import serializer
class BookView(ListCreateAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
class BookViewDetail(RetrieveUpdateDestroyAPIView):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
'''其餘的和第三層一樣'''
第五層:基於ViewSet寫五個介面
檢視集匯入:from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet,ViewSet,GenericViewSet,ViewSetMixin
路由匯入:from rest_framework.routers import SimpleRouter,DefaultRouter
基於ViewSet檢視集寫,需要我們配置路由
-
方法一
from django.urls import path, include from rest_framework.routers import SimpleRouter from app01 import views router = SimpleRouter() router.register('books', views.BookView, 'books') urlpatterns = [ ... ] urlpatterns += router.urls ''' register(self, prefix, viewset, basename=None) prefix:路由url字首 viewset:處理請求的viewset類 basename:路由名稱的字首,一般和prefix寫成一樣就行 ''' # 等同於 path('books/'),include(router.urls) path('books/<int:pk>'),include(router.urls)
-
方法二
router = SimpleRouter() router.register('books', views.BookView, 'books') urlpatterns = [ ... url(r'^', include(router.urls)) ] # 生成兩種路由 path('/api/v1'),include(router.urls) # [<URLPattern '^books/$' [name='books-list']>, <URLPattern '^books/(?P<pk>[^/.]+)/$' [name='books-detail']>] # 等同於自己配的 path('/api/v1/books/'),include(router.urls) path('/api/v1/books/<int:pk>'),include(router.urls)
異同:
-
同:方法一和方法二都可以自動生成路由,代替了下面的路由
path('books/', views.BookView.as_view()), path('books/<int:pk>', views.BookViewDetail.as_view()),
-
異:方法二可以拼接路徑,如果不拼接是和方法一一樣的
-
兩種不同的路由
第五層基於ModelViewSet檢視集寫五個介面demo
views.py
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet,ViewSet,GenericViewSet,ViewSetMixin
class BookView(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import SimpleRouter
from app01 import views
router = SimpleRouter()
router.register('books', views.BookView, 'books')
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/',include(router.urls)),
]
ps:剩下的都一樣~
ReadOnlyModelViewSet檢視集
繼承該ReadOnlyModelViewSet檢視集的作用是隻讀,只做查詢,修改刪除等操作不允許
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet,ViewSet,GenericViewSet,ViewSetMixin
class BookView(ReadOnlyModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
兩個檢視集總結:
- ModelViewSet可以寫五個介面,而ReadOnlyModelViewSet只能寫兩個介面
本質
-
ModelViewSet繼承了五個檢視擴充套件類+GenericViewSet,GenericViewSet繼承了ViewSetMixin+GenericAPIView
PS:ViewSetMixin控制了路由寫法
-
ReadOnlyModelViewSet繼承了RetrieveModelMixin+ListModelMixin+GenericViewSet
其他檢視集
ViewSet
ViewSet = ViewSetMixin+APIView
class ViewSet(ViewSetMixin, views.APIView):
"""
The base ViewSet class does not provide any actions by default.
"""
pass
GenericViewSet
GenericViewSet = ViewSetMixin+GenericAPIView
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
ViewSetMixin
魔術檢視類,控制自動生成路由,可以通過組合繼承,以前的寫法可以繼續使用,但是如果要自動生成路由必須得繼承ViewSetMixin及其子類;或者選擇繼承ViewSet、GenericViewSet
class ViewSetMixin:
"""
This is the magic.
Overrides `.as_view()` so that it takes an `actions` keyword that performs
the binding of HTTP methods to actions on the Resource.
For example, to create a concrete view binding the 'GET' and 'POST' methods
to the 'list' and 'create' actions...
view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
"""
這就是魔法。
重寫' .as_view() ',以便它接受一個' actions '關鍵字執行
將HTTP方法繫結到資源上的動作。
例如,建立繫結'GET'和'POST'方法的具體檢視
到“列表”和“建立”動作…
= MyViewSet檢視。 As_view ({'get': 'list', 'post': 'create'})
總結
-
第一層:基於APIView寫檢視,get、post、put、delete都需要自己寫,序列化的資料和序列化類需要獲取後指定
class BookView(APIView): def get(self, requets): book_list = models.Book.objects.all() ser = serializer.BookSerializer(instance=book_list, many=True) return Response(ser.data)
-
第二層:基於GenericAPIView寫檢視,優化了檢視類內序列化資料和序列化類的程式碼冗餘問題,通過
queryset
和serializer_class
指定序列化集和序列化器即可,一個檢視類內寫一次即可,最後通過get_queryset
和get_serializer
方法處理class BookView(GenericAPIView): queryset = models.Book.objects.all() serializer_class = serializer.BookSerializer def get(self, requets): obj = self.get_queryset() ser = self.get_serializer(instance=obj,many=True) return Response(ser.data)
-
第三層:基於GenericAPIView+5個檢視擴充套件類寫檢視,每個擴充套件類對應一個介面,更加細化,通過繼承父類(擴充套件類)減少了程式碼的冗餘
class BookView(ListModelMixin,CreateModelMixin,GenericAPIView): queryset = models.Book.objects.all() serializer_class = serializer.BookSerializer def get(self, request): return super().list(request)
-
第四層,基於九個檢視子類寫,檢視子類將擴充套件類和GenericAPIView封裝到一塊,使得我們要寫的程式碼更少了,總之就是牛逼~
class BookView(ListCreateAPIView): queryset = models.Book.objects.all() serializer_class = serializer.BookSerializer
-
第五層,基於ViewSet寫檢視,這樣以來5個介面就都在一個檢視類內,程式碼更少了,但是可擴充套件性低了,路由也是問題,get所有和get一條路由衝突需要修改
class BookView(ModelViewSet): queryset = models.Book.objects.all() serializer_class = serializer.BookSerializer '''路由''' router = SimpleRouter() router.register('books', views.BookView, 'books') urlpatterns = [ path('admin/', admin.site.urls), path('api/v1/',include(router.urls)), ]
補充
檢視集中定義附加action動作
在檢視集中,除了上述預設的方法動作外,還可以新增自定義動作。
舉例:
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
class StudentModelViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
def login(self,request):
"""學生登入功能"""
return Response({"message":"登入成功"})
url的定義
urlpatterns = [
path("students8/", views.StudentModelViewSet.as_view({"get": "list", "post": "create"})),
re_path("students8/(?P<pk>\d+)/",
views.StudentModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
path("stu/login/",views.StudentModelViewSet.as_view({"get":"login"}))
]
action屬性
在檢視集中,我們可以通過action物件屬性來獲取當前請求檢視集時的action動作是哪個。
例如:
from rest_framework.viewsets import ModelViewSet
from students.models import Student
from .serializers import StudentModelSerializer
from rest_framework.response import Response
class StudentModelViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
def get_new_5(self,request):
"""獲取最近新增的5個學生資訊"""
# 運算元據庫
print(self.action) # 獲取本次請求的檢視方法名
通過路由訪問到當前方法中.可以看到本次的action就是請求的方法名
累死?,有錯誤請指正~感謝