使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:
ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。
视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。如:
class BookInfoViewSet(viewsets.ViewSet):
def list(self, request):
books = BookInfo.objects.all()
serializer = BookInfoSerializer(books, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
try:
books = BookInfo.objects.get(id=pk)
except BookInfo.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
serializer = BookInfoSerializer(books)
return Response(serializer.data)
在设置路由时,我们可以如下操作
urlpatterns = [
url(r'^books/$', BookInfoViewSet.as_view({'get':'list'}),
url(r'^books/(?P\d+)/$', BookInfoViewSet.as_view({'get': 'retrieve'})
]
继承自APIView与ViewSetMixin,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。
ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{‘get’:‘list’})的映射处理工作。
在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSet
from rest_framework.response import Response
from book.models import BookInfo
from drf_book.serializer import BookSerializer
class BooksViewSet(ViewSet):
"""
获取所有图书和保存图书
"""
# 按照类视图限流,throttle_scope指定类视图限流名称
throttle_scope = 'b'
def list(self, request):
"""
获取所有图书
:param request:
:return:
"""
# 1、查询图书表获取所有图书对象
books = BookInfo.objects.all()
# 2、提取所有对象的字段内容
# 初始化生成序列化器对象
ser = BookSerializer(books, many=True)
# 使用序列化器对象的data方法获取序列化后的结果
data = ser.data
# 3、返回所有对象字段内容
return Response({'book_list': data})
def create(self, request):
"""
保存图书
:param request:
:return:
"""
# 1、获取保存的图书数据
data=request.data
# 2、验证图书数据字段
ser = BookSerializer(data=data)
# is_valid是序列化器的验证方法
ser.is_valid(raise_exception=True) # raise_exception=True 验证失败直接返回
# ser.errors获取验证结果信息
# 3、保存图书
# 调用序列化器中封装保存方法create
ser.save()
return Response(ser.data)
class BookViewSet(ViewSet):
"""
获取单一图书数据
更新图书
删除图书
"""
def retrieve(self, request, pk):
"""
获取单一图书数据
:param request:
:param pk:
:return:
"""
# 1、根据pk值查询图书对象
try:
book = BookInfo.objects.get(id=pk)
except:
return Response({'error': '错误的id值'})
# 2、返回图书数据
ser = BookSerializer(book)
return Response(
ser.data
)
def update(self, request, pk):
"""
更新图书
:param request:
:param pk:
:return:
"""
# 1、获取保存的图书数据
data = request.data
# 2、验证图书数据字段
try:
book = BookInfo.objects.get(id=pk)
except:
return Response({'error': '错误的id值'})
ser = BookSerializer(book, data=data)
# is_valid是序列化器的验证方法
ser.is_valid(raise_exception=True) # raise_exception=True 验证失败直接返回
# 3、更新图书
ser.save()
# # 4、返回保存后的图书数据
return Response(ser.data)
def destroy(self, request, pk):
"""
删除图书
:param request:
:param pk:
:return:
"""
# 1、查询删除的图书对象
try:
book = BookInfo.objects.get(id=pk)
except:
return Response({'error': '错误的id值'})
# 2、逻辑
book.is_delete = True
book.save()
# 物理删除
# book.delete()
# 3、返回结果
return Response({})
from django.conf.urls import url
from django.contrib import admin
from . import views,views_apiview,views_genericapivie,views_mixinview,views_mixinchildview,view_viewset,views_genericvieset,views_modelviewset
from rest_framework.routers import SimpleRouter,DefaultRouter
urlpatterns = [
#视图集路由匹配
url(r'^viewset_books/$', view_viewset.BooksViewSet.as_view({'get':'list','post':'create'})),
url(r'^viewset_books/(?P\d+)/$', view_viewset.BookViewSet.as_view({'get':'retrieve','put':'update'})),
]
# 生成路由类对象
router=DefaultRouter()
router.register('modelviewset_books',views_modelviewset.BookModelViewSet,base_name='book')
# print(router.urls)
urlpatterns += router.urls
使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView,所以还需要继承GenericAPIView。
GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIView与ViewSetMixin,在实现了调用as_view()时传入字典(如{‘get’:‘list’})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。
from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from book.models import BookInfo
from drf_book.serializer import BookSerializer
class BooksGenericViewSet(GenericViewSet):
"""
获取所有图书和保存图书
"""
# 指定查询集属性
queryset = BookInfo.objects.all()
# 指定序列化器
serializer_class = BookSerializer
def list(self, request):
"""
获取所有图书
:param request:
:return:
"""
# 1、查询图书表获取所有图书对象 self.get_queryset() 获取queryset属性中的所有数据
books = self.get_queryset()
# 2、提取所有对象的字段内容
# 初始化生成序列化器对象 self.get_serializer 获取serializer_class所指定的序列化器进行初始化操作
ser = self.get_serializer(books, many=True)
# 使用序列化器对象的data方法获取序列化后的结果
data = ser.data
# 3、返回所有对象字段内容
return Response({'book_list': data})
def create(self, request):
"""
保存图书
:param request:
:return:
"""
# 1、获取保存的图书数据
data = request.data
# 2、验证图书数据字段
ser = self.get_serializer(data=data)
# is_valid是序列化器的验证方法
ser.is_valid(raise_exception=True) # raise_exception=True 验证失败直接返回
# ser.errors获取验证结果信息
# 3、保存图书
# 调用序列化器中封装保存方法create
ser.save()
return Response(ser.data)
class BookGenericViewSet(GenericViewSet):
"""
获取单一图书数据
更新图书
删除图书
"""
# 指定查询集属性
queryset = BookInfo.objects.all()
# 指定序列化器
serializer_class = BookSerializer
def retrieve(self, request, pk):
"""
获取单一图书数据
:param request:
:param pk:
:return:
"""
# 1、根据pk值查询图书对象
try:
# self.get_object()从queryset中获取当前pk所对应的数据对象
book = self.get_object()
except:
return Response({'error': '错误的id值'})
# 2、返回图书数据
ser = self.get_serializer(book)
return Response(
ser.data
)
def update(self, request, pk):
"""
更新图书
:param request:
:param pk:
:return:
"""
# 1、获取保存的图书数据
data = request.data
# 2、验证图书数据字段
try:
book = self.get_object()
except:
return Response({'error': '错误的id值'})
ser = self.get_serializer(book)
# is_valid是序列化器的验证方法
ser.is_valid(raise_exception=True) # raise_exception=True 验证失败直接返回
# 3、更新图书
ser.save()
# # 4、返回保存后的图书数据
return Response(ser.data)
def destroy(self, request, pk):
"""
删除图书
:param request:
:param pk:
:return:
"""
# 1、查询删除的图书对象
try:
book = self.get_serializer()
except:
return Response({'error': '错误的id值'})
# 2、逻辑
book.is_delete = True
book.save()
# 物理删除
# book.delete()
# 3、返回结果
return Response({})
from django.conf.urls import url
from django.contrib import admin
from . import views,views_apiview,views_genericapivie,views_mixinview,views_mixinchildview,view_viewset,views_genericvieset,views_modelviewset
from rest_framework.routers import SimpleRouter,DefaultRouter
urlpatterns = [
# GenericViewSet使用
url(r'^genericviewset_books/$', views_genericvieset.BooksGenericViewSet.as_view({'get': 'list', 'post': 'create'})),
url(r'^genericviewset_books/(?P\d+)/$', views_genericvieset.BookGenericViewSet.as_view({'get': 'retrieve', 'put': 'update'})),
]
# 生成路由类对象
router=DefaultRouter()
router.register('modelviewset_books',views_modelviewset.BookModelViewSet,base_name='book')
# print(router.urls)
urlpatterns += router.urls
继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
from django.db import DatabaseError
from rest_framework.authentication import BasicAuthentication, SessionAuthentication
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.viewsets import ModelViewSet
from rest_framework.filters import OrderingFilter
from book.models import BookInfo
from drf_book.serializer import BookSerializer, BookModelSerializer
from drf_book.utils import PageNum
class BookModelViewSet(ModelViewSet):
# 指定查询集属性
queryset = BookInfo.objects.all()
# 指定序列化器
serializer_class = BookSerializer
from django.conf.urls import url
from django.contrib import admin
from . import views,views_apiview,views_genericapivie,views_mixinview,views_mixinchildview,view_viewset,views_genericvieset,views_modelviewset
from rest_framework.routers import SimpleRouter,DefaultRouter
urlpatterns = [
# ModelViewSet使用
url(r'^modelviewset_books/$',views_modelviewset.BookModelViewSet.as_view({'get': 'list', 'post': 'create'})),
url(r'^modelviewset_books/(?P\d+)/$',views_modelviewset.BookModelViewSet.as_view({'get': 'retrieve', 'put': 'update'})),
]
# 生成路由类对象
router=DefaultRouter()
router.register('modelviewset_books',views_modelviewset.BookModelViewSet,base_name='book')
# print(router.urls)
urlpatterns += router.urls
继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin。
"""经过上面的处理,我们就已经把所有视图方法写在一个类中了,但是继承父类有点多
所以,drf里面提供了模型视图集[ModelViewSet],可以一次性提供5个api接口的方法
最后,def还提供了只读模型视图集[ReadOnlyModelViewSet],可以提供获取多条数据和一条数据的视图方法
"""
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
from rest_framework.decorators import action
class BookModelViewSet(ModelViewSet):
# 指定查询集属性
queryset = BookInfo.objects.all()
# 指定序列化器
serializer_class = BookSerializer
"""
在视图集中,我们还可以通过重写get_serializer或者get_queryset对
同一个类中的指定视图采用不同的queryset或者不同的序列化器
"""
def get_queryset(self):
"""在视图集中视图对象下面会新增一个action属性,用于获取视图方法名"""
if BookInfo.action == "get_top_3":
return BookInfo.objects.filter(sex=True).order_by("-age")[:3]
else:
return BookInfo.objects.all()
# @action(methods=["http请求方法1","http请求方法2",...], detail="是否要生成pk值",url_path="url路径,不填写则默认使用方法名")
@action(methods=["get","put"],detail=True,url_path="getTop")
def get_top_3(self,request):
return self.list(request)
此扩展方法包括:get_serializer_class(获取序列化器返回)、action属性、自定义方法的使用
from django.db import DatabaseError
from rest_framework.authentication import BasicAuthentication, SessionAuthentication
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.viewsets import ModelViewSet
from rest_framework.filters import OrderingFilter
from book.models import BookInfo
from drf_book.serializer import BookSerializer, BookModelSerializer
from drf_book.utils import PageNum
class BookModelViewSet(ModelViewSet):
# 指定查询集属性
queryset = BookInfo.objects.all()
# 指定序列化器
serializer_class = BookSerializer
# 指定认证
# authentication_classes = [BasicAuthentication,SessionAuthentication]
# # 指定权限
# permission_classes = [IsAuthenticated]
# 指定限流用户
# throttle_classes = [UserRateThrottle]
# 按照类视图限流,throttle_scope指定类视图限流名称
# throttle_scope='a'
#指定过滤字段
# filter_fields = ('btitle', 'bread')
# 指定排序后端类
filter_backends = [OrderingFilter]
# 指定排序字段
ordering_fields=('id','bread')
# 指定分页器
pagination_class = PageNum
def get_serializer_class(self):
# get_serializer_class会被get_serializer调用
# 默认返回self.serializer_class
# return self.serializer_class
# self.action 获取前端要请求方法名
if self.action =='last_book':
return BookSerializer
else:
return BookModelSerializer
# 获取最后一本图书数据
@action(methods=['get'],detail=False)
def last_book(self,request):
raise DatabaseError
book=BookInfo.objects.latest('id')
ser=self.get_serializer(book)
return Response(ser.data)
# 按照书名查询数据
@action(methods=['get'], detail=True)
def find(self,request,pk):
data=request.query_params
btitle=data.get('btitle')
book=BookInfo.objects.get(btitle=btitle)
ser = self.get_serializer(book)
return Response(ser.data)
from django.conf.urls import url
from django.contrib import admin
from . import views,views_apiview,views_genericapivie,views_mixinview,views_mixinchildview,view_viewset,views_genericvieset,views_modelviewset
from rest_framework.routers import SimpleRouter,DefaultRouter
urlpatterns = [
# ModelViewSet使用
url(r'^modelviewset_books/$',views_modelviewset.BookModelViewSet.as_view({'get': 'list', 'post': 'create'})),
url(r'^modelviewset_books/(?P\d+)/$',views_modelviewset.BookModelViewSet.as_view({'get': 'retrieve', 'put': 'update'})),
url(r'^modelviewset_books/last_book/$',views_modelviewset.BookModelViewSet.as_view({'get': 'last_book'})),
url(r'^modelviewset_books/find/$',views_modelviewset.BookModelViewSet.as_view({'get': 'find'}))
]
# 生成路由类对象
router=DefaultRouter()
router.register('modelviewset_books',views_modelviewset.BookModelViewSet,base_name='book')
# print(router.urls)
urlpatterns += router.urls