3、DRF实战总结:基于类的视图APIView, GenericAPIView和GenericViewSet视图集(附源码)
前面介绍了什么是符合RESTful规范的API接口,以及使用了基于函数的视图(FBV)编写了对文章进行增删查改的API。在本篇文章将使用基于类的视图(Class-based View, CBV)重写之前的接口。
参考:
1、Django开发总结:Django MVT与MVC设计模式,请求过程与代码示例(附源码)_SteveRocket的博客-CSDN博客如果要开发一个好的网站或网络应用,就必需了解经典的软件开发所遵循的MVC 设计模式。本篇详细总结软件开发所遵循的MVC (Model-View-Controller, 模型-视图-控制器) 设计模式以及Django的MVT设计模式(Model-View-Template)如何遵循这种设计理念。Django Model(模型), URL(链接), View(视图) 和Template(模板)又是如何遵循MVC软件设计模式的。https://blog.csdn.net/zhouruifu2015/article/details/129648966
https://blog.csdn.net/zhouruifu2015/article/details/129761750
https://blog.csdn.net/zhouruifu2015/article/details/129761750
工程路径及APP:django_framework\django_rest_framework_pro\drf_pro
基于类的视图(CBV)
一个中大型的Web项目代码量通常是非常大的,如果全部使用函数视图写,那么代码的复用率是非常低的。而使用类视图,就可以有效的提高代码复用,因为类是可以被继承的,可以拓展的。特别是将一些可以共用的功能抽象成Mixin类或基类后可以减少重复造轮子的工作。
DRF推荐使用基于类的视图(CBV)来开发API, 并提供了4种开发CBV开发模式。
- 使用基础APIView类
- 使用Mixins类和GenericAPI类混配
- 使用通用视图generics.*类, 比如generics.ListCreateAPIView
- 使用视图集ViewSet和ModelViewSet
类视图的比较
DRF提供了4种编写CBV类API的方式,到底哪种CBV开发模式更好? 答案是各有利弊
- 基础的API类:可读性最高,代码最多,灵活性最高。当需要对API行为进行个性化定制时,建议使用这种方式。
- 通用generics.*类:可读性好,代码适中,灵活性较高。当需要对一个模型进行标准的增删查改全部或部分操作时建议使用这种方式。
- 使用视图集viewset: 可读性较低,代码最少,灵活性最低。当需要对一个模型进行标准的增删查改的全部操作且不需定制API行为时建议使用这种方式。
- mixin类和GenericAPI的混用,这个和generics.*类没什么区别,不看也罢。
Django视图集viewset代码最少,但这是以牺牲了代码的可读性为代价的,因为它对代码进行了高度地抽象化。另外urls由router生成,不如自己手动配置的清楚。
使用CBV类可以简化代码,增加代码重用,在很多情况下还需要重写父类的方法,比如get_queryset, get_serializer_class方法以实现特殊的功能。
使用APIView类
DRF的APIView类继承了Django自带的View类, 一样可以按请求方法调用不同的处理函数,比如get方法处理GET请求,post方法处理POST请求。不过DRF的APIView要强大得多。它不仅支持更多请求方法,而且对Django的request对象进行了封装,可以使用request.data获取用户通过POST, PUT和PATCH方法发过来的数据,而且支持插拔式地配置认证、权限和限流类。
使用APIView类重写之前的函数视图
# drf_pro/views.py
# 基础APIView类
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from django.http import Http404
from .models import Article
from .serializers import ArticleSerializer2class ArticleList(APIView):"""List all articles, or create a new article."""def get(self, request, format=None):articles = Article.objects.all()serializer = ArticleSerializer2(articles, many=True)return Response(serializer.data)def post(self, request, format=None):serializer = ArticleSerializer2(data=request.data)if serializer.is_valid():# 注意:手动将request.user与author绑定serializer.save(author=request.user)return Response(serializer.data, status=status.HTTP_201_CREATED)return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)class ArticleDetail(APIView):"""Retrieve, update or delete an article instance."""def get_object(self, pk):try:return Article.objects.get(pk=pk)except Article.DoesNotExist:raise Http404def get(self, request, pk, format=None):article = self.get_object(pk)serializer = ArticleSerializer2(article)return Response(serializer.data)def put(self, request, pk, format=None):article = self.get_object(pk)serializer = ArticleSerializer2(instance=article, data=request.data)if serializer.is_valid():serializer.save()return Response(serializer.data)return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)def delete(self, request, pk, format=None):article = self.get_object(pk)article.delete()return Response(status=status.HTTP_204_NO_CONTENT)
或许已经注意到,这段代码跟之前基于函数的视图差别并不大。最大不同的是不需要在对用户的请求方法进行判断。该视图可以自动将不同请求转发到相应处理方法,逻辑上也更清晰。
修改url配置, 让其指向新的基于类的视图
# drf_pro/urls.py
from django.urls import re_path
from rest_framework.urlpatterns import format_suffix_patterns
from . import views, views_cbvurlpatterns = [re_path(r'^articles/$', views.article_list),re_path(r'^articles/(?P<pk>[0-9]+)$', views.article_detail),# 基于类的视图re_path(r'^articles_cbv/$', views_cbv.ArticleList.as_view()),# http://localhost/v1/articles_cbv/re_path(r'^articles_cbv/(?P<pk>[0-9]+)$', views_cbv.ArticleDetail.as_view()),
]urlpatterns = format_suffix_patterns(urlpatterns=urlpatterns)
发送GET请求到v1/articles_cbv/将看到跟上文一样的效果

发送GET请求到v1/articles_cbv/4/ 根据id查看详情

使用Mixin类和GenericAPI类混配
使用基础APIView类并没有大量简化代码,与增删改查操作相关的代码包括返回内容对所有模型几乎都是一样的。比如现在需要对文章类别Category模型也进行序列化和反序列化,只需要复制Article视图代码,将Article模型改成Category模型, 序列化类由ArticleSeralizer类改成CategorySerializer类就行了。
对于这些通用的增删改查行为,DRF已经提供了相应的Mixin类。Mixin类可与generics.GenericAPI类联用,灵活组合成所需要的视图。
使用Mixin类和generics.GenericAPI类重写的类视图
# drf_pro/views.py
# 使用Mixin类和generics.GenericAPI类重写的类视图
from rest_framework import mixins
from rest_framework import generics
class ArticleList2(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):"""GenericAPIView 类继承了APIView类,提供了基础的API视图。"""queryset = Article.objects.all()serializer_class = ArticleSerializer2def get(self, request, *args, **kwargs):return self.list(request, *args, **kwargs)def post(self, reqeust, *args, **kwargs):return self.create(reqeust, *args, **kwargs)
GenericAPIView 类继承了APIView类,提供了基础的API视图。它对用户请求进行了转发,并对Django自带的request对象进行了封装。不过它比APIView类更强大,因为它还可以通过queryset和serializer_class属性指定需要序列化与反序列化的模型或queryset及所用到的序列化器类。
这里的 ListModelMixin 和 CreateModelMixin类则分别引入了.list() 和 .create() 方法,当用户发送get请求时调用Mixin提供的list()方法,将指定queryset序列化后输出,发送post请求时调用Mixin提供的create()方法,创建新的实例对象。
DRF还提供RetrieveModelMixin, UpdateModelMixin和DestroyModelMixin类,实现了对单个对象实例的查、改和删操作,如下所示:
class ArticleDetail2(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView):queryset = Article.objects.all()serializer_class = ArticleSerializer2def get(self, request, *args, **kwargs):return self.retrieve(request, *args, **kwargs)def put(self, request, *args, **kwargs):return self.update(request, *args, **kwargs)def delete(self, request, *args, **kwargs):return self.destroy(request, *args, **kwargs)
已经有了get, post, delete等方法,为什么mixin类引入的方法要以list, create, retrieve, destroy方法命名?
因为请求方法不如操作名字清晰,比如get方法同时对应了获取对象列表和单个对象两种操作,使用list和retrieve方法后则很容易区分。另外post方法接受用户发过来的请求数据后,有时只需转发不需要创建模型对象实例,所以post方法不能简单等于create方法。
新的ArticleList视图类看似正确,但其实还有一个问题。 定义的序列化器ArticleSeralizer类并不包含author这个字段的,这是因为希望在创建article实例时将author与request.user进行手动绑定。在前面的例子中使用serializer.save(author=request.user)这一方法进行手动绑定。
现在使用mixin类后的操作方法是重写perform_create方法,如下所示:
class ArticleList2(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):"""GenericAPIView 类继承了APIView类,提供了基础的API视图。"""queryset = Article.objects.all()serializer_class = ArticleSerializer2def get(self, request, *args, **kwargs):return self.list(request, *args, **kwargs)def post(self, reqeust, *args, **kwargs):return self.create(reqeust, *args, **kwargs)# 将request.user与author绑定def perform_create(self, serializer):serializer.save(author=self.request.user)
perform_create这个钩子函数是CreateModelMixin类自带的,用于执行创建对象时需要执行的其它方法,比如发送邮件等功能,有点类似于Django的信号。类似的钩子函数还有UpdateModelMixin提供的.perform_update方法和DestroyModelMixin提供的.perform_destroy方法。
urls.py中新定义URL
# 使用Mixin类和generics.GenericAPI类重写的类视图
re_path(r'^articles_cbv2/$', views_cbv.ArticleList2.as_view()),
re_path(r'^articles_cbv2/(?P<pk>[0-9]+)/$', views_cbv.ArticleDetail2.as_view()),
浏览器请求文章列表

浏览器请求单篇文章详情

使用通用视图generics.*类
将Mixin类和GenericAPI类混配,已经帮助减少了一些代码,但还可以做得更好,比如将get请求与mixin提供的list方法进行绑定感觉有些多余。DRF还提供了一套常用的将 Mixin 类与 GenericAPI类已经组合好了的视图,开箱即用,可以进一步简化的代码,如下所示:
from rest_framework import generics
class ArticleList3(generics.ListCreateAPIView):queryset = Article.objects.all()serializer_class = ArticleSerializer2# 将request.user与author绑定def perform_create(self, serializer):serializer.save(author=self.request.user)class ArticleDetail3(generics.RetrieveUpdateAPIView):queryset = Article.objects.all()serializer_class = ArticleSerializer2
generics.ListCreateAPIView类支持List、Create两种视图功能,分别对应GET和POST请求。generics.RetrieveUpdateDestroyAPIView支持Retrieve、Update、Destroy操作,其对应方法分别是GET、PUT和DELETE。
urls.py中新定义URL
# generic class-based views
re_path(r'articles_cbv3/$', views_cbv.ArticleList3.as_view()),
re_path(r'articles_cbv3/(?P<pk>[0-9]+)/$', views_cbv.ArticleDetail3.as_view()),


短短几行代码实现了所有想要的功能,代码更简洁,其它常用generics.*类视图还包括ListAPIView, RetrieveAPIView, RetrieveUpdateAPIView等等。
使用视图集(viewset)
使用通用视图generics.*类后视图代码已经大大简化,但是ArticleList和ArticleDetail两个类中queryset和serializer_class属性依然存在代码重复。使用视图集可以将两个类视图进一步合并,一次性提供List、Create、Retrieve、Update、Destroy这5种常见操作,这样queryset和seralizer_class属性也只需定义一次就好, 如下所示:
# drf_pro/views.py
# 视图集(viewset)
from rest_framework import viewsets
class ArticleViewSet(viewsets.ModelViewSet):# 用一个视图集替代ArticleList和ArticleDetail两个视图queryset = Article.objects.all()serializer_class = ArticleSerializer2# 自行添加,将request.user与author绑定def perform_create(self, serializer):serializer.save(author = self.request.user)
使用视图集后,需要使用DRF提供的路由router来分发urls,因为一个视图集现在对应多个urls的组合,而不像之前的一个url对应一个视图函数或一个视图类。
# drf_pro/urls.py
# 使用视图集后,需要使用DRF提供的路由router来分发urls,因为一个视图集现在对应多个urls的组合
from rest_framework.routers import DefaultRouterrouter = DefaultRouter()
router.register(r'articles4', viewset=views_cbv.ArticleViewSet)
urlpatterns = [
]
urlpatterns += router.urls
浏览器访问


一个视图集对应List、Create、Retrieve、Update、Destroy这5种操作。有时候只需要其中的几种操作,该如何实现?答案是在urls.py中指定方法映射即可,如下所示:
# drf_pro/urls.py
from django.urls import re_path
from rest_framework.urlpatterns import format_suffix_patterns
from . import views, views_cbv# 针对只需要其中的几种操作 使用方法映射
article_list = views_cbv.ArticleViewSet.as_view({'get': 'list','post': 'create'
})
article_detail = views_cbv.ArticleViewSet.as_view({'get': 'retrieve' # 只处理get请求,获取单个记录
})urlpatterns = [# 视图集(viewset)re_path(r'^articles5/$', article_list),re_path(r'^articles5/(?P<pk>[0-9]+)/$', article_detail),
]
另外DRF还提供了ReadOnlyModelViewSet这个类,仅支持list和retrive这个操作。
代码示例:https://download.csdn.net/download/zhouruifu2015/87611605

输入才有输出,吸收才能吐纳。——码字不易![]()
相关文章:
3、DRF实战总结:基于类的视图APIView, GenericAPIView和GenericViewSet视图集(附源码)
前面介绍了什么是符合RESTful规范的API接口,以及使用了基于函数的视图(FBV)编写了对文章进行增删查改的API。在本篇文章将使用基于类的视图(Class-based View, CBV)重写之前的接口。 参考: 1、Django开发总结:Django MVT与MVC设计模式&…...
AutoSAR PduR -AutoSAR PDU常用的使用方式【发送,接收,网关】
总目录链接==>> AutoSAR入门和实战系列总目录 @学前问答: AutoSAR PDU在哪里全局定义的? AutoSAR PDU涉及到哪些模块? AutoSAR PDU网关怎么使用? 文章目录 1 AutoSAR PDU发送2 AutoSAR PDU接收3 AutoSAR PDU网关转发4 答疑解析AutoSAR PDU 怎么样通过PduR 实现与其…...
瑟瑟发抖吧~OpenAI刚刚推出王炸——引入ChatGPT插件,开启AI新生态
5分钟学会使用ChatGPT 插件(ChatGPT plugins)——ChatGPT生态建设的开端ChatGPT插件是什么OpenAI最新官方blog资料表示,已经在ChatGPT中实现了对插件的初步支持。插件是专门为以安全为核心原则的语言模型设计的工具,可帮助ChatGPT…...
脉诊(切脉、诊脉、按脉、持脉)之法——入门篇
认识脉诊何谓脉诊?脉诊的渊源脉诊重要吗?脉诊确有其事,还是故弄玄虚?中医科学吗?如何脉诊?寸口脉诊法何谓脉诊? 所谓脉诊,就是通过把脉来诊断身体健康状况的一种必要手段。 …...
【十二天学java】day09常用api介绍
1.API 1.1API概述 什么是API API (Application Programming Interface) :应用程序编程接口 java中的API 指的就是 JDK 中提供的各种功能的 Java类,这些类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这…...
软件测试 - 测试用例常见面试题
1.测试用例的要素测试用例是为了实施测试而向被测试的系统提供的一组集合, 这组集合包含 : 测试环境, 操作步骤, 测试数据, 预期结果等要素.例如 : 在 B 站输入框输入一个空格, 检查结果测试用例标题 : 输入框输入空格测试环境 : Windows 系统, 谷歌浏览器-版本 111.0.5563.65&…...
几种常见的API接口分页方案
文章目录1 概述2 分页方案2.1 基于偏移量2.2 基于游标3 重复数据处理3.1 基于时间3.2 基于热度3.3 基于推荐1 概述 列表是互联网产品中很常见的一种内容排列形式,而且列表的数据集往往成千上万,一次性返回全量数据集的场景几乎不存在,所以出…...
【Object 类的方法】
在 Java 中,所有类都继承了 Object 类,因此 Object 类中的方法可以在所有 Java 对象中使用。下面是 Object 类中的一些常用方法介绍: equals(Object obj): 用于判断两个对象是否相等。默认情况下,该方法比较的是两个对象的地址是…...
留用户、补内容,在线音乐暗战不停
在线音乐在人们的日常生活中扮演着愈发重要的角色,尤其是在面临巨大压力时,人们往往更倾向于通过倾听一段音乐来缓解内心的紧张与焦虑。而随着在线音乐用户数量的增长以及付费意愿的增强,在线音乐行业也实现了稳步发展。 经过多年的发展&…...
python--exec
在Python中,eval和exec都是用来执行动态代码的内置函数,但它们的作用和使用方式有所不同。 eval(): 将字符串作为Python表达式进行求值,并返回结果。 exec(): 将字符串作为Python语句进行执行,没有返回值。 eval()的使用范围通常限…...
干货分享!这6个高效率办公软件,总有一个值得你收藏!
分享6款高效办公软件,可以解决你很多需求,职场人一定要知道。每一款都是精挑细的,可能有的已经很大众了,但肯定还有小伙伴不知道,废话不多说,直接看!! 1、Flomo笔记:记录…...
代码随想录刷题-链表总结篇
文章目录链表理论基础单链表双链表循环链表其余知识点链表理论基础单链表双链表循环链表其余知识点移除链表元素习题我的解法虚拟头结点解法设计链表习题我的解法代码随想录代码反转链表习题双指针递归两两交换链表中的节点习题我的解法代码随想录解法删除链表的倒数第N个节点习…...
C++:指针:什么是野指针
野指针目录1:定义2:野指针常见情形2.1 :未初始化的野指针2.2 所指的对象已经消亡2.3 指针释放之后未置空3:避免野指针1:定义 指向非法的内存地址的指针叫做野指针(Wild Pointer),也…...
一线大厂高并发Redis缓存架构
文章目录高并发缓存架构设计架构设计思路完整代码开发规范与优化建议键值设计命令使用客户端的使用扩展布隆过滤器redis的过期键的清除策略高并发缓存架构设计 架构设计思路 首先是一个基础的缓存架构,对于新增、修改操作set会对缓存更新,对于查询操作…...
剑指offer-二维数组中的查找
文章目录题目描述题解一 无脑暴力循环题解二 初始二分法🌕博客x主页:己不由心王道长🌕! 🌎文章说明:剑指offer-二维数组中的查找🌎 ✅系列专栏:剑指offer 🌴本篇内容:对剑…...
怎么设计一个秒杀系统
1、系统部署 秒杀系统部署要单独区别开其他系统单独部署,这个系统的流量肯定很大,单独部署。数据库也要单独用一个部署的数据库或者集群,防止高并发导致整个网站不可用。 2、防止超卖 100个库存,1000个人买,要保证不…...
程序参数解析C/C++库 The Lean Mean C++ Option Parser
开发中我们经常使用程序参数,根据参数的不同来实现不同的功能。POSIX和GNU组织对此都制定了一些标准,为了我们程序更为通用标准,建议遵循这些行业内的规范,本文介绍的开源库The Lean Mean C Option Parser就可以很好满足我们的需求…...
Java中的深拷贝和浅拷贝
目录 🍎引出拷贝 🍎浅拷贝 🍎深拷贝 🍎总结 引出拷贝 现在有一个学生类和书包类,在学生类中有引用类型的书包变量: class SchoolBag {private String brand; //书包的品牌private int size; //书…...
大文件上传
上图就是大致的流程一、标题图片上传课程的标题图片Ajax发送请求到后端后端接收到图片使用IO流去保存图片,返回图片的信息对象JS回调函数接收对象通过$("元素id").val(值),方式给页面form表达img标签src属性值,达到上传图片并回显二…...
Python每日一练(20230327)
目录 1. 最大矩形 🌟🌟🌟 2. 反转链表 II 🌟🌟 3. 单词接龙 II 🌟🌟🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
