前言
使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:
list() 提供一组数据
retrieve() 提供单个数据
create() 创建数据
update() 保存数据
destory() 删除数据
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<pk>\d+)/$', BookInfoViewSet.as_view({'get': 'retrieve'}) ]
一、基本视图集
1.ViewSet
继承自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<pk>\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
2.GenericViewSet
使用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
二、扩展视图集
1.ModelViewSet
继承自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
2.ReadOnlyModelViewSet
继承自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)
三、用法补充
1.扩展方法使用
此扩展方法包括: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