Django之ORM与MySQL对比

news2024/9/25 15:23:17

ORM 把类映射成数据库中的表,把类的一个实例对象映射成数据库中的数据行,把类的属性映射成表中的字段,通过对象的操作对应到数据库表的操作,实现了对象到SQL、SQL到对象的转换过程。

ORM 与数据库的映射关系图
下面以一个商品库存明细表 myfirstapp_sku(包含商品编号、货号、颜色、尺码、库存属性字段),分别用ORM和sql语句对该表进行增删改查操作:
在这里插入图片描述

1. 创建表

  • ORM
 class Sku(models.Model):  # 模型类要继承models.Model
    sku = models.IntegerField(max_length=20, verbose_name="商品编号")
    goods_no = models.IntegerField(max_length=20, verbose_name="货号")
    co_val = models.CharField(max_length=20, verbose_name="颜色")
    si_val = models.CharField(max_length=20, verbose_name="尺码")
    sale_stock = models.IntegerField(max_length=20, verbose_name="库存")
  • MySQL
CREATE TABLE `myfirstapp_sku` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `sku` int unsigned NOT NULL AUTO_INCREMENT COMMENT '商品编号',
  `goods_no` int unsigned NOT NULL DEFAULT '0' COMMENT '货号',
  `co_val` varchar(50) NOT NULL DEFAULT '' COMMENT '颜色',
  `si_val` varchar(50) NOT NULL DEFAULT '' COMMENT '尺码',
  `sale_stock ` smallint unsigned NOT NULL DEFAULT '0' COMMENT '库存',
  PRIMARY KEY (`id`)) ;

2. 新增表数据

  • ORM
 Sku(sku='27347162', goods_no='1255600007', co_val='灰色', si_val='XS', sale_stock=88).save()
  • MySQL
INSERT INTO `yishou`.`myfirstapp_sku`(`sku`, `goods_no`, `co_val`, `si_val`, `sale_stock`) VALUES
 ( '27347162', '1255600007', '灰色', 'XS', 70);

3. 查询表数据(下面只列举了ORM)

  • 单条件查询
1. 查询某个条件下,表记录所有字段的值
Sku.objects.filter(sku='27347163').values()

2. 查询某个条件下,表记录某个字段的值
Sku.objects.filter(sku='27347163').values('goods_no')

3. 查询某个条件下,表记录某几个字段的值
Sku.objects.filter(sku='27347163').values('id','sku','goods_no')

补充:
1. Sku.objects.all()--查询表的所有对象
2. Sku.objects.get(sku='27347163')-- 若存在,则返回:Sku object (2);若不存在,则报错:Sku matching query does not exist.
3. Sku.objects.filter(sku='27347161').last()-- 若存在多条记录,查最后一条
4. Sku.objects.filter(sku='27347161').first()-- 若存在多条记录,查第一条
  • 多条件组合查询
# 查询颜色为咖色且尺码为L的所有记录
Sku.objects.filter(Q(co_val='咖色') & Q(si_val='L')).values()

# 查询颜色为咖色或颜色为米色的所有记录
Sku.objects.filter(Q(co_val='咖色') | Q(co_val='米色')).values()

# 查询【颜色为咖色或颜色为米色】且【尺码为L】的所有记录
Sku.objects.filter(Q(co_val='咖色') | Q(co_val='米色'),si_val='L').values()

# 获取sku='27347161'的个数
Sku.objects.filter(sku='27347161').count()
  • 大于/小于查询
******注:以下为双下划线_ _******

# 获取sale_stock大于1的值 
Sku.objects.filter(sale_stock__gt=1)   

# 获取sale_stock大于等于1的值
Sku.objects.filter(sale_stock__gte=1)    
  
# 获取sale_stock小于10的值        
Sku.objects.filter(sale_stock__lt=10)     

# 获取sale_stock小于等于10的值        
Sku.objects.filter(sale_stock__lte=10)  

# 获取sale_stock大于1且小于10的值           
Sku.objects.filter(sale_stock__gt=1, sale_stock__lt=10 )

  • 包含/不包含查询
# 获取sku 等于 27347161、27347163、27347164的数据
Sku.objects.filter(sku__in=[27347161, 27347163, 27347164])   

# 获取sku 不等于 27347161、27347163、27347164的数据,即 not in
Sku.objects.exclude(sku__in=[27347161, 27347163, 27347164]) 

# 模糊查询,查询尺码包含XS的数据
Sku.objects.filter(si_val__contains="XS")

# 模糊查询,查询尺码包含xs、XS、Xs、xS的数据
Sku.objects.filter(si_val__icontains="xs")   # icontains大小写不敏感

# 反向模糊查询,查询尺码不包含xs、XS、Xs、xS的数据
Sku.objects.exclude(si_val__icontains="XS") 

# 范围查询,查询库存在[1,10]的数据
Sku.objects.filter(sale_stock__range=[1, 10])
  • 分组查询
# 查询sku='27347161'所有记录并按照id升序
Sku.objects.filter(sku='27347161').order_by('id')    # asc

# 查询sku='27347161'所有记录并按照id降序
Sku.objects.filter(sku='27347161').order_by('-id')   # desc

# 查询索引在4到6(包含6)的记录
Sku.objects.all()[4:7]
  • 聚合查询
# 查询sku='27347161'所有记录,将相同的goods_no放在一组,返回goods_no、求和的sale_stock 
from django.db.models import Sum

result = Sku.objects.filter(sku=27347161).values('goods_no').annotate(total_sale_stock=Sum('sale_stock'))

for row in result:
    goods_no = row['goods_no']
    total_sale_stock = row['total_sale_stock']
    print(f"Goods No: {goods_no}, Total Sale Stock: {total_sale_stock}")
 
对应sql语句:SELECT goods_no, SUM(sale_stock) as total_sale_stock FROM myfirstapp_sku WHERE sku = 27347161 GROUP BY goods_no;

4. 修改表数据

  • 更新某个条件下,某个字段的值
# 方式1
Sku.objects.filter(sku='27347162').update(sale_stock=99)

# 方式2
sku_obj=models.Sku.objects.get(sku='27347162')
sku_obj.sale_stock=99
sku_obj.save()

对应sql语句:update myfirstapp_sku set sale_stock=99 where sku='27347162';
  • 统一修改表某一列的数据
******F(),可以获取对象中的字段的属性(列),并对其进行操作******
# 对每个sku的库存上调1件
Sku.objects.all().update(sale_stock=F('sale_stock')+1)

对应sql语句:update myfirstapp_sku set sale_stock = sale_stock + 1;

5. 删除表数据

  • ORM
Sku.objects.filter(sku='27347162').delete()
  • MySQL
delete from myfirstapp_sku  where sku='27347162'

从上面的增删改查代码实现来看,大部分场景ORM与sql语句在简易程度上都旗鼓相当,有些场景sql语句甚至更简洁、更直接,为何还要使用ORM呢???

其实当涉及到更复杂的业务逻辑和数据关联时,Django的ORM可以提供可读性更高的代码,而不需要开发者手动编写和维护复杂的SQL语句。举个栗子:

假设我们有三个模型(Model):User(用户)、Group(群组)和Membership(成员关系),一个用户可以加入多个群组,并且在每个群组中拥有一个角色。

  • 使用Django的ORM,可以通过以下方式来查询每个用户所属的群组及其角色:
python
from django.db import models

class User(models.Model):
    name = models.CharField(max_length=100)

class Group(models.Model):
    name = models.CharField(max_length=100)

class Membership(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    role = models.CharField(max_length=100)

# 查询每个用户所属的群组及其角色
users = User.objects.all()
for user in users:
    memberships = Membership.objects.select_related('group').filter(user=user)
    for membership in memberships:
        print(f"用户名:{user.name},群组名:{membership.group.name},角色:{membership.role}")

ps:使用select_related方法进行关联查询,以避免N+1查询问题,然后使用filter方法过滤出每个用户的成员关系。最后,我们迭代每个用户的成员关系,并打印用户、群组和角色名称
  • 相比之下,如果使用Mysql直接操作数据库,需要编写更复杂的SQL语句来实现相同的功能:
# 该SQL语句使用了多个JOIN和别名(AS)操作来关联查询,并选择所需的字段。这样的SQL语句相对较长和复杂,且容易出错。
SELECT
    u.name,
    g.name AS group_name,
    m.role
FROM
    user u
JOIN
    membership m ON m.user_id = u.id
JOIN
    group g ON g.id = m.group_id;

6. 总结

从两者对数据库表的增删改查操作来看,Django的ORM操作数据库SQL语句直接操作数据库 确实存在一些相同点与不同点:

相同点:

  • 数据库操作:都可以进行常见的数据库增、删、改、查操作;
  • 连接方式:都需要建立与数据库的连接,以便进行数据交互;
  • 数据库支持:都支持各种主流数据库,包括MySQL、PostgreSQL、SQLite、Oracle等;

区别点:

  • 语法:Django的ORM使用类和方法的方式进行数据库操作,而Mysql直接操作数据库需要编写SQL语句。ORM提供了一种更加简洁、抽象和面向对象的数据库访问方式;
  • 复杂性:对于简单和快速的数据库操作,Mysql直接操作数据库可能更加直观和高效。但是对于复杂的业务逻辑和数据关联,Django的ORM能够提供更好的抽象和封装,简化开发流程,并且减少对SQL语句的依赖;
  • 数据库迁移:Django的ORM提供了数据库迁移工具,可以方便地进行数据库结构的变更和迁移。而Mysql直接操作数据库需要手动编写和执行SQL语句来实现数据库的变更;

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

spring boot/spring cloud项目中创建Moudel子模块出现 Ignored pom.xml

出现问题: 在 IDEA 项目的父工程中创建了子模块,但是由于子模块创建有误,删了后重新创建,出现了 Ignored pom.xml 的问题。 分析问题: 分析原因:应该是 IDEA 觉得这个项目已经被你删除了,所以…

pandas (十) 缺失值的处理:填充、删除、过滤、查询

Pandas使用函数处理缺失值 isnull和notnull:检测是否是空值,可用于df和seriesdropna:丢弃、删除余缺失值 axis: 删除行还是列,{0 or ‘index’, 1 or ‘columns’), default 0 how: 如果等于any则任何值为空都删除,如…

630到期,全面整改完成!

2023年6月30日对于消费金融行业的同学来讲,是一个大日子。 因为在2022年7月12日的时候,银监会特意下发了一个通知,《提升金融服务质效的通知》,原文见文末。 里面要求各金融机构进行相应整改,而整改的截止日期就是2023…

C++ 多线程

多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序。一般情况下,两种类型的多任务处理:基于进程和基于线程。 基于进程的多任务处理是程序的并发执行。基于线程的多任务处理是同一程序的片段的并发执行。…

Unity GameFramework StarForce 流程介绍

一、游戏总入口 GameEntry 1.内建好的GameEntry.Builtin 提供了各种框架的组件封装 2.自定义GameEntry.Custom 根据提供的案例参考即可实现自己的组件 3.游戏入口GameEntry 二、实现自己的组件并注册到管理类中 我们自己的组件只需要继承UnityGameFramework.Runtime.Gam…

实现数据库增删改产+界面效果2-----jsp

任务 1.通过连接数据库完成用户登录模块。 2.登录成功后查询出一张数据库表中的内容;登录不成功返回登录页面。 3.登录页面端要有空值和非法字符验证。 4.登录成功后对一张表中数据进行增加、删除、修改和查询操作。 代码 数据库相关代码 创建数据库 名字为jdb…

76、基于STM32单片机车牌识别摄像头图像处理扫描设计(程序+原理图+PCB源文件+相关资料+参考PPT+元器件清单等)

单片机主芯片选择方案 方案一:AT89C51是美国ATMEL公司生产的低电压,高性能CMOS型8位单片机,器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器(CPU)和Flash存储单元&a…

阿里拿38K出来的大佬良心分享,熬夜整理10 万字详细Java面试笔记

国内的互联网面试,恐怕是现存的、最接近科举考试的制度。 这是由于互联网IT行业的求职者太多了,如果考察的是清一溜的算法题和设计题,那么会要求面试官有极高的技术水平,还要花大量的时间成本和精力。 所以,八股文面…

#systemverilog# 关于随机约束之 unique 关键字

前言 在随机约束中,我们可以使用关键字 unique 。 使用关键字unique定义的SystemVerilog约束称为唯一约束。在随机化中,使用唯一约束可以生成变量集的唯一值或数组的唯一元素。这里着重解释一下变量集:是同一类型随机变量的集合。 通过unique约束我们可以完成以下任务: …

详解c++---哈希桶

目录标题 闭散列的回顾拉链法/哈希桶的原理准备工作find函数插入函数erase函数析构函数代码测试insert函数的改进 闭散列的回顾 在前面的学习中我们知道了闭散列的运算规则,当两个数据计算得到的位置发生冲突时,它会自动的往后寻找没有发生冲突的位置&a…

樽海鞘群算法(SSA)(含MATLAB代码)

先做一个声明:文章是由我的个人公众号中的推送直接复制粘贴而来,因此对智能优化算法感兴趣的朋友,可关注我的个人公众号:启发式算法讨论。我会不定期在公众号里分享不同的智能优化算法,经典的,或者是近几年…

时间序列分解 | Matlab自适应噪音的完整集合经验模态分解CEEMDAN分解

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 时间序列分解 | Matlab自适应噪音的完整集合经验模态分解CEEMDAN分解 部分源码 %--------------------

torch_scatter安装踩坑实录

由于运行代码出现如下报错 ModuleNotFoundError: No module named torch_scatter因此,在网上找到一篇博客【不好使】 pip install torch-scatter -f https://pytorch-geometric.com/whl/torch-1.12.1cu116.html(match) F:\matchCode\SuperGlue_training-main>p…

Bootstrap 表格

文章目录 Bootstrap 表格基本的表格可选的表格类条纹表格边框表格悬停表格精简表格 上下文类响应式表格 Bootstrap 表格 Bootstrap 提供了一个清晰的创建表格的布局。下表列出了 Bootstrap 支持的一些表格元素&#xff1a; 标签描述<table>为表格添加基础样式。<thea…

学习笔记-图解HTTP

1 Web及网络基础 1.1 适用Http协议访问Web 在浏览器上输入网址然后访问指定的网页&#xff0c;浏览器就相当于是客户端&#xff0c;访问的网址就是指向特定的服务器。 HTTP协议&#xff1a;HyperText Transfer Protocol&#xff0c;超文本传输协议。 Web是建立在HTTP协议上…

MySQL8.0安装详细教程

前言&#xff1a; MySQL版本区别&#xff1a; ● MySQL Community Server&#xff1a;Community是社区版本&#xff0c;开源免费&#xff0c;但不提供官方技术支持&#xff1b; ● MySQL Enterprise Edition&#xff1a;Enterprise企业版本&#xff0c;需付费&#xff0c;可以…

剑指 Offer 数组中数字出现的次数

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;数组中数字出现的次数 ⭕️ 代码&#xff1a; /*思路&#xff1a;有两个出现单次的数字&#xff0c;其余数字都出现两次。把所有的数字分成两组&#xff0c;这两个数组分到不同的组&#xff0c;异或起来&#xff0c;就可…

力扣 108. 将有序数组转换为二叉搜索树

题目来源&#xff1a;https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/description/ C题解1&#xff1a;递归法。由于要求是平衡树&#xff0c;又给出了递增数组&#xff0c;所以构建二叉树只需将中间值作为中间节点&#xff0c;左右两边分属左右子树…

无广告 齐全 简洁 免费的音乐开源软件(支持 电脑max win linux 手机 )——lxMusic

无广告 齐全 简洁 免费的音乐开源软件&#xff08;支持 电脑max win linux 手机 &#xff09;——lxMusic 话不多说先上效果 &#xff08;真香&#xff09; 下载地址&#xff08;官方&#xff09; https://www.lanzoui.com/b0bf2cfa/ 密码&#xff1a;glqw 软件安装包说明 文…

python接口自动化(五)--接口测试用例和接口测试报告模板(详解)

简介 当今社会在测试领域&#xff0c;接口测试已经越来越多的被提及&#xff0c;被重视&#xff0c;而且现在好多招聘信息要对接口测试提出要求。区别于传统意义上的系统级别测试&#xff0c;很多测试人员在接触到接口测试的时候&#xff0c;也许对测试执行还可以比较顺利的上手…