3、DRF实战总结:基于类的视图APIView, GenericAPIView和GenericViewSet视图集(附源码)

news/2024/5/5 1:21:23/文章来源:https://blog.csdn.net/zhouruifu2015/article/details/129761752

前面介绍了什么是符合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/129761750icon-default.png?t=N2N8https://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

输入才有输出,吸收才能吐纳。——码字不易

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_277010.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用EPPlus加载excel数据

环境 Unity:2021.3.6f1c1 EPPlus:5.8.14 net.3.5 准备 使用Nuget下载EPPlus,找到 net3.5中的EPPlus.dll文件&#xff0c;导入Unity的Plugins文件夹创建一个xlsx(excel)文件,测试内容如下图 . 表格内容解释 第一行解释第二行的内容&#xff0c; 第二行对应变量名称&#xff0…

Python采集商品数据信息,做数据可视化分析,又是对数据分析上心的一天

前言 环境使用 在开始之前&#xff0c;安装好我们的代码编辑器和环境是非常重要的 Python 3.8pycharm --> 编辑器jupyter notebook --> 数据分析编辑器 模块使用 requests >>> pip install requests 数据请求parsel >>> pip install parsel 数据解…

openKylin社区首届咨询委员会会议成功召开!

2023年3月25日&#xff0c;openKylin社区首届咨询委员会会议在北京成功召开。中国工程院院士廖湘科、倪光南、方滨兴、桂卫华、郑纬民、王耀南&#xff0c;中国电子学会秘书长陈英&#xff0c;中国软件行业协会秘书长吕卫锋&#xff0c;原航天工程大学教授邹鹏&#xff0c;共创…

一起来学5G终端射频标准(TAE for UL-MIMO)

01—TAE的定义我们先来了解一下TAE测试标准的发展演变。在4G LTE的3GPP 36.101-1的技术要求规范中&#xff0c;就给出了对4G终端UL MIMO以及V2X UE的TAE的定义和最小要求&#xff0c;但在36.521-1的4G终端一致性测试规范中并没有对应的章节规定TAE的一致性测试。5G中有所变化&a…

华中师范大学研究生学位论文规范及排版技巧

研究生学位论文规范研究生学位论文是学位申请者获取博士、硕士学位的重要依据&#xff0c;是研究生科研能力、科研成果的集中体现&#xff0c;同时也是重要的社会文献资料。为了规范学位论文撰写&#xff0c;提高我校研究生学位论文质量&#xff0c;根据GB/T7713-1987《科学技术…

每天学一点之Servlet

一、web资源 1、web资源的概念 将web应用部署到tomcat中&#xff0c;web应用中所有的内容都是服务器中的资源 2、web资源的分类 web资源的分类&#xff1a;web应用中src中编写的动态资源&#xff0c;web应用中web中编写的静态资源 静态资源&#xff1a;每次访问时&#xf…

复杂链表的复制-剑指Offer35-java

一、题目描述 请实现 copyRandomList 函数&#xff0c;复制一个复杂链表。在复杂链表中&#xff0c;每个节点除了有一个 next 指针指向下一个节点&#xff0c;还有一个 random 指针指向链表中的任意节点或者 null。 示例 1&#xff1a; 输入&#xff1a;head [[7,null],[13,…

ChartGPT多重插补法 填充缺失点

问题描述已知时间戳与对应的值&#xff0c;需要根据时间戳找到缺失的点&#xff0c;然后进行值的填充。例如&#xff1a;源码<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-math3 --><dependency><groupId>org.apache.commons</gr…

flink执行任务运行10h以后挂掉并且报错

问题描述flink运行jar包任务&#xff0c;运行几个小时或者1天以后&#xff0c;任务就会挂掉&#xff01;&#xff01;&#xff01;第一个错误是2023-02-01 23:43:08,083 INFO org.apache.flink.runtime.executiongraph.ExecutionGraph [] - Window(TumblingEventTimeWindows(60…

【Unity】创建一个自己的AR安卓程序

目录1 环境配置2 下载官方提供的AR Starter工程3 AR Starter工程中的包以及打包设置3.1 Package Manager3.2 Player Settings4 创建一个新的AR场景5 AR场景中的物体6 在unity中运行AR场景7 在AR场景的基础上添加自己的想法7.1 修改Cube的旋转速度/方向7.2 将Cube替换为其他物体…

今年面试好激烈!

金三银四过去一半&#xff0c;市场火热&#xff0c;但是大家就业压力却没有缓解多少。 很多粉丝后台留言&#xff0c;Java程序员面临的竞争太激烈了…… 我自己也有实感&#xff0c;多年身处一线互联网公司&#xff0c;虽没有直面过求职跳槽的残酷&#xff0c;但经常担任技术面…

【开发实践】在线考试系统(一) 生成错题知识点的思维导图

一、需求分析设计 笔者开发了一个在线考试系统&#xff0c;导师提出一个需求&#xff1a;添加对考试错题相关知识点的总结。 在question表中关联知识点的编号&#xff0c;题目可能关联多个知识点。这里笔者的设计是&#xff0c;只关联一个知识点&#xff0c;便于维护。 下面是知…

【python实操】马上毕业了,你还不懂什么是守护线程、线程、进程?(附12306抢票程序-源代码)

作者&#xff1a;20岁爱吃必胜客&#xff08;坤制作人&#xff09;&#xff0c;近十年开发经验, 跨域学习者&#xff0c;目前于海外某世界知名高校就读计算机相关专业。荣誉&#xff1a;阿里云博客专家认证、腾讯开发者社区优质创作者&#xff0c;在CTF省赛校赛多次取得好成绩。…

预训练语言模型(GPT,BERT)

文章目录GPT 模型预训练语言模型模型和学习BERT 模型去噪自编码器模型和学习模型特点References在自然语言处理中事先使用大规模语料学习基于 Transformer 等的语言模型&#xff0c;之后用于各种任务的学习和预测&#xff0c;称这种模型为预训练语言模型。代表性的模型有 BERT …

LCX端口转发之远程桌面端口双重映射多主机转发

1.下载LCX端口转发工具源码及程序: git clone https://github.com/UndefinedIdentifier/LCX lcx1 2.复制到目标机: winxp win2003 win7

上海亚商投顾:创业板指低开高走ChatGPT概念股再爆发

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。市场情绪大小指数今日走势分化&#xff0c;沪指盘中一度跌超1%&#xff0c;午后震荡回升跌幅收窄&#xff0c;创业板指则低开…

iOS多线程——GCD学习总结

文章目录多线程编程进程线程线程与进程的关系CPU核GCD简介为什么我们要使用GCD任务同步执行&#xff08;sync&#xff09;&#xff1a;异步执行&#xff08;async&#xff09;&#xff1a;队列&#xff08;Dispatch Queue&#xff09;串行队列&#xff08;Serial Dispatch Queu…

Tensor高阶用法:快速掌握Tensor切分、变形等方法

要想在实际的应用中更灵活地用好 Tensor&#xff0c;Tensor 的连接、切分等操作也是必不可少的。我们就通过一些例子和图片来一块学习下。虽然这几个操作比较有难度&#xff0c;但只要耐心分析&#xff0c;然后上手练习&#xff0c;还是可以拿下的。 Tensor 的连接操作 在项目…

SQL语法基础

简介 SQL (Structured Query Language) 是具有数据操纵和数据定义等多种功能的数据库语言&#xff0c;这种语言具有交互性特点&#xff0c;能为用户提供极大的便利&#xff0c;数据库管理系统应充分利用SQL语言提高计算机应用系统的工作质量与效率。 以下介绍postgresql语法&am…

ChatGPT的多种用法(持续更新中。。。)

指南 写小说 “写一本拥有出人意料结局的推理小说。” “写一个让读者参与其中的交互小说。” “为孩子们写一本激励他们勇敢面对挑战的小说。” “编写一个有关科技创新的未来世界的小说。” “创造一个让读者感到沉浸其中的幻想故事。” 充当 Linux 终端 我想让你充当…