【愚公系列】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
相关文章
|
21天前
|
人工智能 开发者 Python
Chainlit:一个开源的异步Python框架,快速构建生产级对话式 AI 应用
Chainlit 是一个开源的异步 Python 框架,帮助开发者在几分钟内构建可扩展的对话式 AI 或代理应用,支持多种工具和服务集成。
126 9
|
1月前
|
JSON 安全 中间件
Python Web 框架 FastAPI
FastAPI 是一个现代的 Python Web 框架,专为快速构建 API 和在线应用而设计。它凭借速度、简单性和开发人员友好的特性迅速走红。FastAPI 支持自动文档生成、类型提示、数据验证、异步操作和依赖注入等功能,极大提升了开发效率并减少了错误。安装简单,使用 pip 安装 FastAPI 和 uvicorn 即可开始开发。其优点包括高性能、自动数据验证和身份验证支持,但也存在学习曲线和社区资源相对较少的缺点。
78 15
|
1月前
|
关系型数据库 API 数据库
Python流行orm框架对比
Python中有多个流行的ORM框架,如SQLAlchemy、Django ORM、Peewee、Tortoise ORM、Pony ORM、SQLModel和GINO。每个框架各有特点,适用于不同的项目需求。SQLAlchemy功能强大且灵活,适合复杂项目;Django ORM与Django框架无缝集成,易用性强;Peewee轻量级且简单,适合小型项目;Tortoise ORM专为异步框架设计;Pony ORM查询语法直观;SQLModel结合Pydantic,适合FastAPI;GINO则适合异步环境开发。初学者推荐使用Django ORM或Peewee,因其易学易用。
|
1月前
|
人工智能 分布式计算 大数据
MaxFrame 产品评测:大数据与AI融合的Python分布式计算框架
MaxFrame是阿里云MaxCompute推出的自研Python分布式计算框架,支持大规模数据处理与AI应用。它提供类似Pandas的API,简化开发流程,并兼容多种机器学习库,加速模型训练前的数据准备。MaxFrame融合大数据和AI,提升效率、促进协作、增强创新能力。尽管初次配置稍显复杂,但其强大的功能集、性能优化及开放性使其成为现代企业与研究机构的理想选择。未来有望进一步简化使用门槛并加强社区建设。
76 7
|
Python
python:教学工具:随机点名提问答卷
开发需求:一共x道题目,给y个学生抓阄答题.
1909 0
|
2月前
|
人工智能 数据可视化 数据挖掘
探索Python编程:从基础到高级
在这篇文章中,我们将一起深入探索Python编程的世界。无论你是初学者还是有经验的程序员,都可以从中获得新的知识和技能。我们将从Python的基础语法开始,然后逐步过渡到更复杂的主题,如面向对象编程、异常处理和模块使用。最后,我们将通过一些实际的代码示例,来展示如何应用这些知识解决实际问题。让我们一起开启Python编程的旅程吧!
|
2月前
|
存储 数据采集 人工智能
Python编程入门:从零基础到实战应用
本文是一篇面向初学者的Python编程教程,旨在帮助读者从零开始学习Python编程语言。文章首先介绍了Python的基本概念和特点,然后通过一个简单的例子展示了如何编写Python代码。接下来,文章详细介绍了Python的数据类型、变量、运算符、控制结构、函数等基本语法知识。最后,文章通过一个实战项目——制作一个简单的计算器程序,帮助读者巩固所学知识并提高编程技能。
|
2月前
|
Unix Linux 程序员
[oeasy]python053_学编程为什么从hello_world_开始
视频介绍了“Hello World”程序的由来及其在编程中的重要性。从贝尔实验室诞生的Unix系统和C语言说起,讲述了“Hello World”作为经典示例的起源和流传过程。文章还探讨了C语言对其他编程语言的影响,以及它在系统编程中的地位。最后总结了“Hello World”、print、小括号和双引号等编程概念的来源。
126 80
|
22天前
|
存储 缓存 Java
Python高性能编程:五种核心优化技术的原理与Python代码
Python在高性能应用场景中常因执行速度不及C、C++等编译型语言而受质疑,但通过合理利用标准库的优化特性,如`__slots__`机制、列表推导式、`@lru_cache`装饰器和生成器等,可以显著提升代码效率。本文详细介绍了这些实用的性能优化技术,帮助开发者在不牺牲代码质量的前提下提高程序性能。实验数据表明,这些优化方法能在内存使用和计算效率方面带来显著改进,适用于大规模数据处理、递归计算等场景。
58 5
Python高性能编程:五种核心优化技术的原理与Python代码
|
2月前
|
Python
[oeasy]python055_python编程_容易出现的问题_函数名的重新赋值_print_int
本文介绍了Python编程中容易出现的问题,特别是函数名、类名和模块名的重新赋值。通过具体示例展示了将内建函数(如`print`、`int`、`max`)或模块名(如`os`)重新赋值为其他类型后,会导致原有功能失效。例如,将`print`赋值为整数后,无法再用其输出内容;将`int`赋值为整数后,无法再进行类型转换。重新赋值后,这些名称失去了原有的功能,可能导致程序错误。总结指出,已有的函数名、类名和模块名不适合覆盖赋新值,否则会失去原有功能。如果需要使用类似的变量名,建议采用其他命名方式以避免冲突。
51 14

热门文章

最新文章