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

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

前言

image.png

使用视图集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
相关文章
|
2月前
|
存储 Java 数据处理
(numpy)Python做数据处理必备框架!(一):认识numpy;从概念层面开始学习ndarray数组:形状、数组转置、数值范围、矩阵...
Numpy是什么? numpy是Python中科学计算的基础包。 它是一个Python库,提供多维数组对象、各种派生对象(例如掩码数组和矩阵)以及用于对数组进行快速操作的各种方法,包括数学、逻辑、形状操作、排序、选择、I/0 、离散傅里叶变换、基本线性代数、基本统计运算、随机模拟等等。 Numpy能做什么? numpy的部分功能如下: ndarray,一个具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组 用于对整组数据进行快速运算的标准数学函数(无需编写循环)。 用于读写磁盘数据的工具以及用于操作内存映射文件的工具。 线性代数、随机数生成以及傅里叶变换功能。 用于集成由C、C++
365 1
|
2月前
|
Java 数据处理 索引
(Pandas)Python做数据处理必选框架之一!(二):附带案例分析;刨析DataFrame结构和其属性;学会访问具体元素;判断元素是否存在;元素求和、求标准值、方差、去重、删除、排序...
DataFrame结构 每一列都属于Series类型,不同列之间数据类型可以不一样,但同一列的值类型必须一致。 DataFrame拥有一个总的 idx记录列,该列记录了每一行的索引 在DataFrame中,若列之间的元素个数不匹配,且使用Series填充时,在DataFrame里空值会显示为NaN;当列之间元素个数不匹配,并且不使用Series填充,会报错。在指定了index 属性显示情况下,会按照index的位置进行排序,默认是 [0,1,2,3,...] 从0索引开始正序排序行。
294 0
|
2月前
|
Java 数据挖掘 数据处理
(Pandas)Python做数据处理必选框架之一!(一):介绍Pandas中的两个数据结构;刨析Series:如何访问数据;数据去重、取众数、总和、标准差、方差、平均值等;判断缺失值、获取索引...
Pandas 是一个开源的数据分析和数据处理库,它是基于 Python 编程语言的。 Pandas 提供了易于使用的数据结构和数据分析工具,特别适用于处理结构化数据,如表格型数据(类似于Excel表格)。 Pandas 是数据科学和分析领域中常用的工具之一,它使得用户能够轻松地从各种数据源中导入数据,并对数据进行高效的操作和分析。 Pandas 主要引入了两种新的数据结构:Series 和 DataFrame。
473 0
|
2月前
|
Java 数据处理 索引
(numpy)Python做数据处理必备框架!(二):ndarray切片的使用与运算;常见的ndarray函数:平方根、正余弦、自然对数、指数、幂等运算;统计函数:方差、均值、极差;比较函数...
ndarray切片 索引从0开始 索引/切片类型 描述/用法 基本索引 通过整数索引直接访问元素。 行/列切片 使用冒号:切片语法选择行或列的子集 连续切片 从起始索引到结束索引按步长切片 使用slice函数 通过slice(start,stop,strp)定义切片规则 布尔索引 通过布尔条件筛选满足条件的元素。支持逻辑运算符 &、|。
199 0
|
测试技术 Python
Python接口自动化测试框架(基础篇)-- 流程控制之循环语句for&while
本文介绍了Python中的循环语句,包括while和for循环的使用,range()函数的运用,以及continue、break和pass关键字的说明,同时提出了关于while循环是否能与成员运算符结合使用的思考。
217 1
Python接口自动化测试框架(基础篇)-- 流程控制之循环语句for&while
|
测试技术 索引 Python
Python接口自动化测试框架(练习篇)-- 数据类型及控制流程(一)
本文提供了Python接口自动化测试中的编程练习,包括计算器、猜数字、猜拳和九九乘法表等经典问题,涵盖了数据类型、运算、循环、条件控制等基础知识的综合应用。
215 1
|
9月前
|
机器学习/深度学习 设计模式 测试技术
Python 高级编程与实战:构建自动化测试框架
本文深入探讨了Python中的自动化测试框架,包括unittest、pytest和nose2,并通过实战项目帮助读者掌握这些技术。文中详细介绍了各框架的基本用法和示例代码,助力开发者快速验证代码正确性,减少手动测试工作量。学习资源推荐包括Python官方文档及Real Python等网站。
|
Java 测试技术 持续交付
【入门思路】基于Python+Unittest+Appium+Excel+BeautifulReport的App/移动端UI自动化测试框架搭建思路
本文重点讲解如何搭建App自动化测试框架的思路,而非完整源码。主要内容包括实现目的、框架设计、环境依赖和框架的主要组成部分。适用于初学者,旨在帮助其快速掌握App自动化测试的基本技能。文中详细介绍了从需求分析到技术栈选择,再到具体模块的封装与实现,包括登录、截图、日志、测试报告和邮件服务等。同时提供了运行效果的展示,便于理解和实践。
887 4
【入门思路】基于Python+Unittest+Appium+Excel+BeautifulReport的App/移动端UI自动化测试框架搭建思路
|
敏捷开发 测试技术 持续交付
自动化测试之美:从零开始搭建你的Python测试框架
在软件开发的马拉松赛道上,自动化测试是那个能让你保持节奏、避免跌宕起伏的神奇小助手。本文将带你走进自动化测试的世界,用Python这把钥匙,解锁高效、可靠的测试框架之门。你将学会如何步步为营,构建属于自己的测试庇护所,让代码质量成为晨跑时清新的空气,而不是雾霾中的忧虑。让我们一起摆脱手动测试的繁琐枷锁,拥抱自动化带来的自由吧!
|
IDE 测试技术 开发工具
Python接口自动化测试框架(基础篇)-- 不只是txt的文件操作
本文介绍了Python中的文件操作方法,包括使用open()打开文件、close()关闭文件、read()读取内容、readline()读取单行、readlines()读取多行、write()写入内容以及writelines()写入多行的方法。同时,探讨了文件操作模式和编码问题,并扩展了上下文管理器with...as的使用,以及对图片和音频文件操作的思考和练习。
162 1
Python接口自动化测试框架(基础篇)-- 不只是txt的文件操作

推荐镜像

更多