【django】Django REST Framework 构建 API:APIView 与 ViewSet
目录
1、APIView
2、ViewSet
3、APIVIew例子
3.1 模型定义
3.2 序列化器定义
3.3 使用视图
3.3.1 ProductListCreateAPIView 类
3.3.2 ProductRetrieveUpdateDestroyAPIView 类
3.4 配置url
3.5 测试
3.5.1 查询全部
3.5.2 添加产品
3.5.3 查询单个产品
3.5.4 修改单个产品
3.5.5 删除单个产品
4、VIEWSet例子
4.1 模型定义
4.2 序列化器定义
4.3 使用视图
4.4 配置url
4.5 测试
4.5.1 查询全部
4.5.2 添加产品
4.5.3 查询单个产品
4.5.4 修改单个产品
4.5.5 删除单个产品
5、总结
5.1 APIView
5.2 ViewSet
前言:针对drf框架对比APIView与ViewSet的优缺点与示例,建议先看上一篇【django】Django REST Framework 序列化与反序列化详解-CSDN博客
1、APIView
APIView 类是 DRF 中最基本的类视图。它继承自 Django 的 View 类,并添加了对请求解析、认证、权限检查等的支持。使用 APIView 可以让你更细粒度地控制每个 HTTP 方法的行为。
优点
细粒度控制:你可以完全控制每个 HTTP 方法的行为。
灵活性:适用于需要复杂逻辑的场景。
缺点
冗余代码:对于简单的 CRUD 操作,可能会导致代码重复。
维护成本:随着功能增加,代码量会变得庞大且难以维护。
2、ViewSet
ViewSet 提供了一种更简洁的方式来处理常见的 CRUD 操作。它允许你将多个相关的操作组合在一起,从而减少代码冗余并提高可维护性。
优点
简洁:自动处理常见的 CRUD 操作,减少了代码量。
一致性:提供了一致的 URL 结构和行为。
易于扩展:可以通过覆盖方法轻松扩展功能。
缺点
抽象程度高:对于非常复杂的业务逻辑,可能需要更多的定制。
学习曲线:初学者可能需要时间来理解 ViewSet 的工作原理。
3、APIVIew例子
3.1 模型定义
假设我们有一个简单的库存管理系统,包含以下三张表:Category(类别)、Product(产品)和 Supplier(供应商)。我们将基于这些表来实现类似于之前 Book 表的 CRUD 操作
# newapp/models.py
from django.db import modelsclass Category(models.Model):name = models.CharField(max_length=100)description = models.TextField(blank=True, null=True)def __str__(self):return self.nameclass Supplier(models.Model):name = models.CharField(max_length=100)contact_person = models.CharField(max_length=100, blank=True, null=True)email = models.EmailField(blank=True, null=True)phone = models.CharField(max_length=20, blank=True, null=True)def __str__(self):return self.nameclass Product(models.Model):name = models.CharField(max_length=255)category = models.ForeignKey(Category, on_delete=models.CASCADE)supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)price = models.DecimalField(max_digits=10, decimal_places=2)stock_quantity = models.IntegerField()description = models.TextField(blank=True, null=True)def __str__(self):return self.name
3.2 序列化器定义
# newapp/serializers.py
from rest_framework import serializers
from .models import Category, Product, Supplierclass CategorySerializer(serializers.ModelSerializer):class Meta:model = Categoryfields = ['id', 'name', 'description']class SupplierSerializer(serializers.ModelSerializer):class Meta:model = Supplierfields = ['id', 'name', 'contact_person', 'email', 'phone']class ProductSerializer(serializers.ModelSerializer):# 用于写入的字段category_id = serializers.PrimaryKeyRelatedField(queryset=Category.objects.all(),source='category',write_only=True,required=True # 确保这个字段是必填的)supplier_id = serializers.PrimaryKeyRelatedField(queryset=Supplier.objects.all(),source='supplier',write_only=True,required=True # 确保这个字段是必填的)# 用于读取的嵌套字段category = CategorySerializer(read_only=True)supplier = SupplierSerializer(read_only=True)class Meta:model = Productfields = ['id', 'name', 'category_id', 'category', 'supplier_id', 'supplier','price', 'stock_quantity', 'description']def create(self, validated_data):category = validated_data.pop('category')supplier = validated_data.pop('supplier')product = Product.objects.create(category=category,supplier=supplier,**validated_data)return productdef update(self, instance, validated_data):if 'category' in validated_data:instance.category = validated_data.pop('category')if 'supplier' in validated_data:instance.supplier = validated_data.pop('supplier')for attr, value in validated_data.items():setattr(instance, attr, value)instance.save()return instancedef validate(self, data):if 'category' not in data or 'supplier' not in data:raise serializers.ValidationError("Both category_id and supplier_id are required.")return data
3.3 使用视图
我们定义两个基于 APIView 的视图类,分别处理产品的列表和创建操作,以及单个产品的获取、更新和删除操作。
3.3.1 ProductListCreateAPIView 类
# newapp/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Product
from .serializers import ProductSerializerclass ProductListCreateAPIView(APIView):def get(self, request):products = Product.objects.all()serializer = ProductSerializer(products, many=True)return Response(serializer.data)def post(self, request):serializer = ProductSerializer(data=request.data)if serializer.is_valid():serializer.save()return Response(serializer.data, status=status.HTTP_201_CREATED)return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
3.3.2 ProductRetrieveUpdateDestroyAPIView 类
class ProductRetrieveUpdateDestroyAPIView(APIView):def get_object(self, pk):try:return Product.objects.get(pk=pk)except Product.DoesNotExist:return Nonedef get(self, request, pk):product = self.get_object(pk)if not product:return Response(status=status.HTTP_404_NOT_FOUND)serializer = ProductSerializer(product)return Response(serializer.data)def put(self, request, pk):product = self.get_object(pk)if not product:return Response(status=status.HTTP_404_NOT_FOUND)serializer = ProductSerializer(product, 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):product = self.get_object(pk)if not product:return Response(status=status.HTTP_404_NOT_FOUND)product.delete()return Response(status=status.HTTP_204_NO_CONTENT)
3.4 配置url
# newapp/urls.py
from django.urls import path
from .views import ProductListCreateAPIView, ProductRetrieveUpdateDestroyAPIViewurlpatterns = [path('products/', ProductListCreateAPIView.as_view(), name='product-list-create'),path('products/<int:pk>/', ProductRetrieveUpdateDestroyAPIView.as_view(), name='product-retrieve-update-destroy'),
]
3.5 测试
3.5.1 查询全部
http://127.0.0.1:8000/drf/products/
[{"id": 1,"name": "空调","category": {"id": 1,"name": "家电","description": ""},"supplier": {"id": 3,"name": "格力","contact_person": "董明珠","email": null,"phone": null},"price": "3459.00","stock_quantity": 100,"description": ""},{"id": 2,"name": "空调","category": {"id": 1,"name": "家电","description": ""},"supplier": {"id": 2,"name": "海信","contact_person": "贾少谦","email": null,"phone": null},"price": "2300.00","stock_quantity": 5,"description": ""},{"id": 3,"name": "电视","category": {"id": 1,"name": "家电","description": ""},"supplier": {"id": 1,"name": "TCL","contact_person": "彭攀","email": null,"phone": null},"price": "2500.00","stock_quantity": 5,"description": ""},{"id": 4,"name": "电视","category": {"id": 1,"name": "家电","description": ""},"supplier": {"id": 2,"name": "海信","contact_person": "贾少谦","email": null,"phone": null},"price": "2700.00","stock_quantity": 2,"description": ""},{"id": 5,"name": "热水器","category": {"id": 2,"name": "厨卫","description": ""},"supplier": {"id": 4,"name": "万家乐","contact_person": "罗潘","email": null,"phone": null},"price": "1600.00","stock_quantity": 5,"description": ""}
]
3.5.2 添加产品
http://127.0.0.1:8000/drf/products/
请求体
{"name": "电视","category_id": 1,"supplier_id": 5,"price": "2599.99","stock_quantity": 50,"description": "新增库存"
}

3.5.3 查询单个产品
http://127.0.0.1:8000/drf/products/8/

3.5.4 修改单个产品
http://127.0.0.1:8000/drf/products/8/
请求体
{"name": "电视333","category_id": 1,"supplier_id": 5,"price": "2599.99","stock_quantity": 1,"description": "修改库存"
}

3.5.5 删除单个产品
http://127.0.0.1:8000/drf/products/8/
4、VIEWSet例子
4.1 模型定义
模型不变,同上
4.2 序列化器定义
不变,同上
4.3 使用视图
# newapp/views.py
from rest_framework import viewsets
from .models import Category, Product, Supplier
from .serializers import CategorySerializer, ProductSerializer, SupplierSerializerclass CategoryViewSet(viewsets.ModelViewSet):queryset = Category.objects.all()serializer_class = CategorySerializerclass SupplierViewSet(viewsets.ModelViewSet):queryset = Supplier.objects.all()serializer_class = SupplierSerializerclass ProductViewSet(viewsets.ModelViewSet):queryset = Product.objects.all()serializer_class = ProductSerializer
4.4 配置url
# newapp/urls.py
from django.urls import path
from rest_framework.routers import SimpleRouter
from .views import CategoryViewSet, ProductViewSet, SupplierViewSet# 创建一个默认的路由器实例
router = DefaultRouter()# 注册视图集到路由器
router.register(r'categories', CategoryViewSet)
router.register(r'suppliers', SupplierViewSet)
router.register(r'product', ProductViewSet)urlpatterns += router.urls
4.5 测试
4.5.1 查询全部
http://127.0.0.1:8000/drf/product/
[{"id": 1,"name": "空调","category": {"id": 1,"name": "家电","description": ""},"supplier": {"id": 3,"name": "格力","contact_person": "董明珠","email": null,"phone": null},"price": "3459.00","stock_quantity": 100,"description": ""},{"id": 2,"name": "空调","category": {"id": 1,"name": "家电","description": ""},"supplier": {"id": 2,"name": "海信","contact_person": "贾少谦","email": null,"phone": null},"price": "2300.00","stock_quantity": 5,"description": ""},{"id": 3,"name": "电视","category": {"id": 1,"name": "家电","description": ""},"supplier": {"id": 1,"name": "TCL","contact_person": "彭攀","email": null,"phone": null},"price": "2500.00","stock_quantity": 5,"description": ""},{"id": 4,"name": "电视","category": {"id": 1,"name": "家电","description": ""},"supplier": {"id": 2,"name": "海信","contact_person": "贾少谦","email": null,"phone": null},"price": "2700.00","stock_quantity": 2,"description": ""},{"id": 5,"name": "热水器","category": {"id": 2,"name": "厨卫","description": ""},"supplier": {"id": 4,"name": "万家乐","contact_person": "罗潘","email": null,"phone": null},"price": "1600.00","stock_quantity": 5,"description": ""},{"id": 6,"name": "电视","category": {"id": 1,"name": "家电","description": ""},"supplier": {"id": 5,"name": "长虹","contact_person": "柳江","email": null,"phone": null},"price": "2599.99","stock_quantity": 50,"description": "新增库存"}
]
4.5.2 添加产品
http://127.0.0.1:8000/drf/product/
请求体
{"name": "电视888待删除","category_id": 1,"supplier_id": 5,"price": "1222","stock_quantity": 1,"description": ""
}

4.5.3 查询单个产品
http://127.0.0.1:8000/drf/product/1/

4.5.4 修改单个产品
http://127.0.0.1:8000/drf/product/9/

4.5.5 删除单个产品
http://127.0.0.1:8000/drf/product/9/
5、总结
通过上述两个示例,你可以看到使用 `APIView` 和 `ViewSet` 实现 CRUD 操作的不同方式。以下是两者的比较:
5.1 APIView
- - 更细粒度的控制。
- - 适用于需要复杂逻辑的场景。
- - 代码量相对较多,但更灵活。
5.2 ViewSet
- - 自动处理常见的 CRUD 操作。
- - 代码简洁,易于维护。
- - 提供了一致的 URL 结构和行为。
选择哪种方式取决于你的具体需求。如果你需要更多的灵活性和细粒度的控制,可以选择 `APIView`。如果你希望快速实现标准的 CRUD 功能并减少代码量,`ViewSet` 是更好的选择。
希望这个完整的示例对你有帮助!如果有任何问题或需要进一步的解释,请随时提问。
相关文章:
【django】Django REST Framework 构建 API:APIView 与 ViewSet
目录 1、APIView 2、ViewSet 3、APIVIew例子 3.1 模型定义 3.2 序列化器定义 3.3 使用视图 3.3.1 ProductListCreateAPIView 类 3.3.2 ProductRetrieveUpdateDestroyAPIView 类 3.4 配置url 3.5 测试 3.5.1 查询全部 3.5.2 添加产品 3.5.3 查询单个产品 3.5.4 修…...
TOEIC 词汇专题:旅游计划篇
TOEIC 词汇专题:旅游计划篇 制定旅行计划时,尤其是跨国旅游,会涉及到很多独特的英语词汇。以下是与“旅游计划”相关的托业词汇,帮助你更加自如地规划行程。 1. 旅行服务和优惠 出发前了解一下与服务和优惠相关的常用词汇&#…...
第三次RHCSA作业
1、配置网络:为网卡添加一个本网段IPV4地址,x.x.x.123 2、配置yum本地仓库,并完成traceroute命令的安装 yum库配置成功过后,显示这个报错,没能写完 3、用至少两种方法查看sshd服务的进程号 4、添加一块10G大小的磁盘&…...
WebGL(Web Graphics Library)
WebGL(Web Graphics Library)是一种基于 JavaScript 的 API,允许在网页上渲染高性能的 2D 和 3D 图形。它利用计算机的 GPU 来实现硬件加速,因此适合创建游戏、数据可视化和交互式应用程序。 WebGL 的基本概念: 上下文…...
Unity核心笔记
1、认识模型的制作 1.建模 2.展UV 3.材质和纹理贴图 4.骨骼绑定 5.动画制作 总结 2、图片导入概述 1.Unity支持的图片格式 2.图片设置的6大部分 3、纹理类型设置 1.纹理类型主要是设置什么 2.参数讲解 4、纹理形状设置 1.纹理形状主要设置什么 2.参数讲解 5、纹理高级设置 …...
数据挖掘(六)
数据挖掘(六) 文章目录 数据挖掘(六)消除歧义从Twitter下载数据加载数据集并分类文本转换器词袋N元语法其他特征朴素贝叶斯贝叶斯定理朴素贝叶斯算法算法应用实例应用抽取特征将字典转换为矩阵训练朴素贝叶斯分类器组装所有的部件完整代码本文使用朴素贝叶斯进行社会媒体挖…...
Netty 组件介绍 - Channel
主要作用 close()可以用来关闭 channelcloseFuture()用来处理 channel 的关闭sync方法作用是同步等待 channel 关闭而 addListener 方法是异步等待 channel 关闭pipeline()方法添加处理器write()方法将数据写入writeAndFlush()方法将数据写入并刷出...
时间序列预测(十)——长短期记忆网络(LSTM)
目录 一、LSTM结构 二、LSTM 核心思想 三、LSTM分步演练 (一)初始化 1、权重和偏置初始化 2、初始细胞状态和隐藏状态初始化 (二)前向传播 1、遗忘门计算(决定从上一时刻隐状态中丢弃多少信息) 2、…...
Flink CDC 同步 Mysql 数据
文章目录 一、Flink CDC、Flink、CDC各有啥关系1.1 概述1.2 和 jdbc Connectors 对比 二、使用2.1 Mysql 打开 bin-log 功能2.2 在 Mysql 中建库建表准备2.3 遇到的坑2.4 测试 三、番外 一、Flink CDC、Flink、CDC各有啥关系 Flink:流式计算框架,不包含 …...
【python实战】-- 根据文件名分类
系列文章目录 文章目录 系列文章目录前言一、根据文件名分类到不同文件夹总结 前言 一、根据文件名分类到不同文件夹 汇总指定目录下所有满足条件的文件到新文件夹 import os import shutil import globsource_dir rD:\Users\gxcaoty\Desktop\39642 # 源目录路径 destinatio…...
蓝桥双周赛 第21场 小白入门赛
1 动态密码 思路:可以直接填空也可以写程序 void solve() {int a 20241111;stack<int> stk;while(a){stk.push(a % 2);a / 2;}while(stk.size()){cout << stk.top();stk.pop();}} 2 购物车里的宝贝 思路:总体异或和为0即可说明可分成一样…...
Linux 进程间通信 共享内存_消息队列_信号量
共享内存 共享内存是一种进程间通信(IPC)机制,它允许多个进程访问同一块内存区域。这种方法可以提高效率,因为数据不需要在进程之间复制,而是可以直接在共享的内存空间中读写。 使用共享内存的步骤通常包括:…...
Mybatis自定义日志打印
一,目标 替换?为具体的参数值统计sql执行时间记录执行时间过长的sql,并输出信息到文档(以天为单位进行存储) 平常打印出来的sql都是sql一行,参数一行。如图: 二,理论 这里我们主要通过Mybatis…...
【在Linux世界中追寻伟大的One Piece】Socket编程TCP(续)
目录 1 -> V2 -Echo Server多进程版本 2 -> V3 -Echo Server多线程版本 3 -> V3-1 -多线程远程命令执行 4 -> V4 -Echo Server线程池版本 1 -> V2 -Echo Server多进程版本 通过每个请求,创建子进程的方式来支持多连接。 InetAddr.hpp #pragma…...
面试高频问题:C/C++编译时内存五个分区
在面试时,C/C++编译时内存五个分区是经常问到的问题,面试官通过这个问题来考察面试者对底层的理解。在平时开发时,懂编译时内存分区,也有助于自己更好管理内存。 目录 内存分区的定义 内存分区的重要性 代码区 数据区 BSS区 堆区 栈区 静态内存分配 动态内存分配…...
阅读博士论文《功率IGBT模块健康状态监测方法研究》
IGBT的失效可以分为芯片级失效和封装级失效。其中封装级失效是IGBT模块老化的主要原因,是多种因素共同作用的结果。在DBC的这种结构中,流过芯片的负载电流通过键合线传导到 DBC上层铜箔,再经过端子流出模块。DBC与芯片和提供机械支撑的基板之…...
Spring ApplicationContext接口
ApplicationContext接口是Spring框架中更高级的IoC容器接口,扩展了BeanFactory接口,提供了更多的企业级功能。ApplicationContext不仅具备BeanFactory的所有功能,还增加了事件发布、国际化、AOP、资源加载等功能。 ApplicationContext接口的…...
[perl] 数组与哈希
数组变量以 符号开始,元素放在括号内 简单举例如下 #!/usr/bin/perl names ("a1", "a2", "a3");print "\$names[0] $names[0]\n"; print "size: ",scalar names,"\n";$new_names shift(names); …...
电机学习-SPWM原理及其MATLAB模型
SPWM原理及其MATLAB模型 一、SPWM原理二、基于零序分量注入的SPWM三、MATLAB模型 一、SPWM原理 SPWM其实是相电压的控制方式,定义三相正弦相电压的表达式: { V a m V m sin ω t V b m V m sin ( ω t − 2 3 π ) V c m V m sin ( ω t 2…...
群控系统服务端开发模式-应用开发-腾讯云上传工厂及七牛云上传工厂开发
记住业务流程图,要不然不清楚自己封装的是什么东西。 一、腾讯云工厂开发 切记在根目录下要安装腾讯云OSS插件,具体代码如下: composer require qcloud/cos-sdk-v5 在根目录下extend文件夹下Upload文件夹下channel文件夹中,我们修…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...
Python训练营-Day26-函数专题1:函数定义与参数
题目1:计算圆的面积 任务: 编写一个名为 calculate_circle_area 的函数,该函数接收圆的半径 radius 作为参数,并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求:函数接收一个位置参数 radi…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...
