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

举报
愚公搬代码 发表于 2022/04/18 22:11:01 2022/04/18
【摘要】 前言使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:list() 提供一组数据retrieve() 提供单个数据create() 创建数据update() 保存数据destory() 删除数据ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。视图集只在使用as_view()方法的时候,才会将...

前言

在这里插入图片描述
使用视图集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<pk>\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<pk>\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<pk>\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
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。