当前位置: 首页 > news >正文

【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 词汇专题&#xff1a;旅游计划篇 制定旅行计划时&#xff0c;尤其是跨国旅游&#xff0c;会涉及到很多独特的英语词汇。以下是与“旅游计划”相关的托业词汇&#xff0c;帮助你更加自如地规划行程。 1. 旅行服务和优惠 出发前了解一下与服务和优惠相关的常用词汇&#…...

第三次RHCSA作业

1、配置网络&#xff1a;为网卡添加一个本网段IPV4地址&#xff0c;x.x.x.123 2、配置yum本地仓库&#xff0c;并完成traceroute命令的安装 yum库配置成功过后&#xff0c;显示这个报错&#xff0c;没能写完 3、用至少两种方法查看sshd服务的进程号 4、添加一块10G大小的磁盘&…...

WebGL(Web Graphics Library)

WebGL&#xff08;Web Graphics Library&#xff09;是一种基于 JavaScript 的 API&#xff0c;允许在网页上渲染高性能的 2D 和 3D 图形。它利用计算机的 GPU 来实现硬件加速&#xff0c;因此适合创建游戏、数据可视化和交互式应用程序。 WebGL 的基本概念&#xff1a; 上下文…...

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分步演练 &#xff08;一&#xff09;初始化 1、权重和偏置初始化 2、初始细胞状态和隐藏状态初始化 &#xff08;二&#xff09;前向传播 1、遗忘门计算&#xff08;决定从上一时刻隐状态中丢弃多少信息&#xff09; 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&#xff1a;流式计算框架&#xff0c;不包含 …...

【python实战】-- 根据文件名分类

系列文章目录 文章目录 系列文章目录前言一、根据文件名分类到不同文件夹总结 前言 一、根据文件名分类到不同文件夹 汇总指定目录下所有满足条件的文件到新文件夹 import os import shutil import globsource_dir rD:\Users\gxcaoty\Desktop\39642 # 源目录路径 destinatio…...

蓝桥双周赛 第21场 小白入门赛

1 动态密码 思路&#xff1a;可以直接填空也可以写程序 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 购物车里的宝贝 思路&#xff1a;总体异或和为0即可说明可分成一样…...

Linux 进程间通信 共享内存_消息队列_信号量

共享内存 共享内存是一种进程间通信&#xff08;IPC&#xff09;机制&#xff0c;它允许多个进程访问同一块内存区域。这种方法可以提高效率&#xff0c;因为数据不需要在进程之间复制&#xff0c;而是可以直接在共享的内存空间中读写。 使用共享内存的步骤通常包括&#xff1a…...

Mybatis自定义日志打印

一&#xff0c;目标 替换?为具体的参数值统计sql执行时间记录执行时间过长的sql&#xff0c;并输出信息到文档&#xff08;以天为单位进行存储&#xff09; 平常打印出来的sql都是sql一行&#xff0c;参数一行。如图&#xff1a; 二&#xff0c;理论 这里我们主要通过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多进程版本 通过每个请求&#xff0c;创建子进程的方式来支持多连接。 InetAddr.hpp #pragma…...

面试高频问题:C/C++编译时内存五个分区

在面试时,C/C++编译时内存五个分区是经常问到的问题,面试官通过这个问题来考察面试者对底层的理解。在平时开发时,懂编译时内存分区,也有助于自己更好管理内存。 目录 内存分区的定义 内存分区的重要性 代码区 数据区 BSS区 堆区 栈区 静态内存分配 动态内存分配…...

阅读博士论文《功率IGBT模块健康状态监测方法研究》

IGBT的失效可以分为芯片级失效和封装级失效。其中封装级失效是IGBT模块老化的主要原因&#xff0c;是多种因素共同作用的结果。在DBC的这种结构中&#xff0c;流过芯片的负载电流通过键合线传导到 DBC上层铜箔&#xff0c;再经过端子流出模块。DBC与芯片和提供机械支撑的基板之…...

Spring ApplicationContext接口

ApplicationContext接口是Spring框架中更高级的IoC容器接口&#xff0c;扩展了BeanFactory接口&#xff0c;提供了更多的企业级功能。ApplicationContext不仅具备BeanFactory的所有功能&#xff0c;还增加了事件发布、国际化、AOP、资源加载等功能。 ApplicationContext接口的…...

[perl] 数组与哈希

数组变量以 符号开始&#xff0c;元素放在括号内 简单举例如下 #!/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其实是相电压的控制方式&#xff0c;定义三相正弦相电压的表达式&#xff1a; { V a m V m sin ⁡ ω t V b m V m sin ⁡ ( ω t − 2 3 π ) V c m V m sin ⁡ ( ω t 2…...

群控系统服务端开发模式-应用开发-腾讯云上传工厂及七牛云上传工厂开发

记住业务流程图&#xff0c;要不然不清楚自己封装的是什么东西。 一、腾讯云工厂开发 切记在根目录下要安装腾讯云OSS插件&#xff0c;具体代码如下&#xff1a; composer require qcloud/cos-sdk-v5 在根目录下extend文件夹下Upload文件夹下channel文件夹中&#xff0c;我们修…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...