前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【愚公系列】2022年04月 Python教学课程 70-DRF框架之视图集

【愚公系列】2022年04月 Python教学课程 70-DRF框架之视图集

作者头像
愚公搬代码
发布2022-04-19 09:25:30
1.6K0
发布2022-04-19 09:25:30
举报
文章被收录于专栏:历史专栏

文章目录

前言

使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:

  • list() 提供一组数据
  • retrieve() 提供单个数据
  • create() 创建数据
  • update() 保存数据
  • destory() 删除数据

ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。

视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。如:

代码语言:javascript
复制
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)

在设置路由时,我们可以如下操作

代码语言:javascript
复制
urlpatterns = [
    url(r'^books/$', BookInfoViewSet.as_view({'get':'list'}),
    url(r'^books/(?P\d+)/$', BookInfoViewSet.as_view({'get': 'retrieve'})
]

一、基本视图集

1.ViewSet

继承自APIView与ViewSetMixin,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。

ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{‘get’:‘list’})的映射处理工作。

在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。

代码语言:javascript
复制
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({})
代码语言:javascript
复制
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

2.GenericViewSet

使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView,所以还需要继承GenericAPIView。

GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIView与ViewSetMixin,在实现了调用as_view()时传入字典(如{‘get’:‘list’})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。

代码语言:javascript
复制
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({})
代码语言:javascript
复制
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。

代码语言:javascript
复制
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
代码语言:javascript
复制
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。

代码语言:javascript
复制
"""经过上面的处理,我们就已经把所有视图方法写在一个类中了,但是继承父类有点多
所以,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属性、自定义方法的使用

代码语言:javascript
复制
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)
代码语言:javascript
复制
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
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022/04/18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 前言
  • 一、基本视图集
    • 1.ViewSet
      • 2.GenericViewSet
      • 二、扩展视图集
        • 1.ModelViewSet
          • 2.ReadOnlyModelViewSet
          • 三、用法补充
            • 1.扩展方法使用
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档