Django-ORM 单表查询

2023-11-19

目录

数据准备

查询关键字

1. QuerySet 对象

first方法

last方法

values方法

values_list 方法

count()

exists()

2. all()

3. filter(**kwargs)

4. get(**kwargs)  不推荐使用

5. exclude(*kwargs)

6. order_by(*field)

7. reverse()

8. distinct()

基于双下划线的模糊查询

__in >>> 成员运算

__range >>> 范围查询

字段中包含某些字符

F查询与Q查询

F查询

根据F查询统一修改字段的值

Q查询

聚合查询

分组查询

单表分组查询

多表分组查询


数据准备

models.py 文件

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    publish_time = models.DateField(auto_now_add=True)
    
    def __str__(self):
        return '书籍_%s 对象'% self.title

tests.py

import os

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_ORM.settings")

    import django
    django.setup()

    from app01 import models
    models.Book.objects.create(title='三国志',price='123.23')
    models.Book.objects.create(title='三国演义',price='133.23')
    models.Book.objects.create(title='水浒传',price='223.23')

查询关键字

1. QuerySet 对象

当使用一些查询语句之后, 获得的返回值会是,<QuerySet [...]>形式

QuerySet 对象中放着符合查询条件的整个记录的对象,注意是一个个的对象 ,并且是整个记录的, 不是某个字段的值, 该方法会获取所有的记录对象, 并且ORM会自动做一个limit限制展示(默认在21个左右)这个列表可以索引取值,但是不能用负数. 推荐使用的内置方法是res.first(), res.last()

只要是QuerySet对象, 就可以.query查看SQL语句

first方法

获取QuerySet对象列表中的首个对象

last方法

获取QuerySet对象列表中的最后一个对象

values方法

只拿到指定的字段的值__ 字典类型.  注意, 返回的是一个QuerySet对象

res = models.Book.objects.values('title','price')
print(res)

# <QuerySet [{'title': '三国志', 'price': Decimal('123.23')}, 
#							{'title': '三国演义', 'price': Decimal('133.23')}, 
#							{'title': '水浒传', 'price': Decimal('223.23')}]>

values_list 方法

只拿到指定字段的值, ____列表套元组类型, 注意: 返回的是一个QuerySet对象

res = models.Book.objects.values_list('title','price')
print(res)

"""
<QuerySet [
	('三国志', Decimal('123.23')), 
	('三国演义', Decimal('133.23')), 
	('水浒传', Decimal('223.23'))
]>
"""

count()

返回匹配查询(QuerySet)的对象数量

exists()

如果QuerySet包含数据,就返回True,否则fanhui False

2. all()

查询所有记录

models.User.objects.all() 返回一个QuerySet对象

res = models.Book.objects.all()
print(res)
# <QuerySet [<Book: 书籍_三国志 对象>, <Book: 书籍_三国演义 对象>, <Book: 书籍_水浒传 对象>]>

3. filter(**kwargs)

查询单条记录核心代码

当我们筛选的字段为主键时, pk可以代替所有主键的具体名称, 而不用具体输入主键的字段

# 去数据库中查询数据
from app01 import models
res = models.User.objects.filter(pk=1)
print(res)
# <QuerySet [<Book: 书籍_三国志 对象>]>

# models.User.objects.filter(**{......})

models.User.objects.filter(username=user_name)匹配成功的返回值是一个列表,匹配失败返回值就是None

filter(username=user_namepassword=pwd)-----filter 括号内可以携带多个参数, 参数之间相当于'and'的关系,必须全部为真才能匹配成功

res = models.User.objects.filter()
print(res)
# <QuerySet [<Book: 书籍_三国志 对象>, <Book: 书籍_三国演义 对象>, <Book: 书籍_水浒传 对象>]>

所以,filter括号内不传筛选条件, 相当于获得表中所有的记录对象

4. get(**kwargs)  不推荐使用

res = models.Book.objects.get(pk=1)
print(res)

# 书籍_三国志 对象

5. exclude(*kwargs)

它包含了与所给筛选条件不匹配的对象

res = models.Book.objects.exclude(pk=1)
print(res)

# <QuerySet [<Book: 书籍_三国演义 对象>, <Book: 书籍_水浒传 对象>]>

6. order_by(*field)

对查询结果排序, 默认升序, 降序则需要在字段前加上一个符号

注意,可以同时放多个字段,按照从左到右的顺序排序, 越靠近左侧,优先级越高, 当遇到结果相同的字段会按照右边的字段依次排序

res = models.Book.objects.order_by('price')
print(res)
# <QuerySet [<Book: 书籍_三国志 对象>, <Book: 书籍_三国演义 对象>, <Book: 书籍_水浒传 对象>]>

res = models.Book.objects.order_by('-price')
print(res)
# <QuerySet [<Book: 书籍_水浒传 对象>, <Book: 书籍_三国演义 对象>, <Book: 书籍_三国志 对象>]>

7. reverse()

对查询结果反向排序,通常只能在具有已定义顺序的QuerySet上调用,(在modle类的Meta中指定ordering或者调用order_by()方法

res = models.Book.objects.order_by('price')
print(res)
# <QuerySet [<Book: 书籍_三国志 对象>, <Book: 书籍_三国演义 对象>, <Book: 书籍_水浒传 对象>]>

res = models.Book.objects.order_by('price').reverse()
print(res)
# <QuerySet [<Book: 书籍_水浒传 对象>, <Book: 书籍_三国演义 对象>, <Book: 书籍_三国志 对象>]>

8. distinct()

注意, ORM去重,会考虑主键,也就是说不能直接对Query Set中的单个对象去重

models.Book.objects.create(title='三国志',price='123.23')
res = models.Book.objects.distinct()
print(res)

# <QuerySet [<Book: 书籍_三国志 对象>, <Book: 书籍_三国演义 对象>, <Book: 书籍_水浒传 对象>, <Book: 书籍_三国志 对象>]>

res = models.Book.objects.values('title').distinct()
print(res)
# <QuerySet [{'title': '三国志'}, {'title': '三国演义'}, {'title': '水浒传'}]>

基于双下划线的模糊查询

__gt >>>大于

__lt >>>小于

__gte >>>大于等于

__lte >>> 小于等于

# 1.查询年龄大于20的用户
res = models.User.objects.filter(age__gt = 20)

__in >>> 成员运算

# 2.查询年龄是18、22、25的用户
res = models.User.objects.filter(age__in=[18, 22, 25])

__range >>> 范围查询

# 3.查询年龄在18到26之间的用户
res = models.User.objects.filter(age__range=[18, 26])  # 包含18和26

字段中包含某些字符

__contains >>> 区分大小写

__icontains >>> 不区分大小写

# 4.查询姓名中包含字母j的用户
res = models.User.objects.filter(name__contains='j')
res = models.User.objects.filter(name__icontains='j')

__year >>> 按照年份筛选数据

__month >>> 按照月份筛选数据

注意数据的日期格式, 可以查询一些其他的日期格式

# 查询月份是5月的数据
res = models.User.objects.filter(op_time__month=8)

# 查询年份是22年的数据
res = models.User.objects.filter(op_time__year=2022)

补充:

__startswith >>> 区分大小写

__endswith >>> 区分大小写

__regex >>> 

F查询与Q查询

F查询

在上边所有的例子中, 我们构造的过滤器都只是将字段值与某个我们自己设定的常量作比较, 如果我们要对两个字段的值作比较, 那该怎么做呢?

Django提供了F()来做这样的比较 , F()的实例可以在在查询中引用字段, 来比较用一个model实例中两个不同字段的值

使用方法:  .filter(筛选字段的方式=F("字段"))

例如: 查询卖出数量大于库存数量的商品

from django.db.models import F
res = models.Book.objects.filter(storage_-gt=F('sold'))
print(res)

根据F查询统一修改字段的值

例如: 将每个商品的价格都提高100元

from django.db.models import F
res = models.Book.objects.update*price = F('price')+100)
print(res)

针对字符串不能直接拼接, 需要导入别的模块

from django.db.models import F
from django.db.models.functions import Concat

res = models.Book.objects.update(name=Concat(F('name')),Value('爆款'))
print(res)

Q查询

filter()方法中逗号隔开的条件是''的关系. 如果需要执行更加复杂的查询,(OR语句), 就可以使用Q对象

例如: AND-----逗号,

res = Book.objects.filter(title='三国演义',number=1000)
print(res)
print(res.query)
# <QuerySet [<Book: Book object>]>
# select * from app01_book where(`app01_book`.`title` = 三国演义 AND `app01_book`.`number` = 1000)
from django.db.models import Q
res = Book.objects.filter(Q(title='三国演义'),Q(number=1000))
print(res.query)
# select * from app01_book where(`app01_book`.`title` = 三国演义 AND `app01_book`.`number` = 1000)

OR----管道符 |

from django.db.models import Q
res = Book.objects.filter(Q(title='三国演义')|Q(number=1000))
print(res.query)
# select * from app01_book where(`app01_book`.`title` = 三国演义 OR `app01_book`.`number` = 1000)

NOT---波良号 ~

from django.db.models import Q
res = Book.objects.filter(~Q(title='三国演义')|Q(number=1000))
print(res.query)
# select * from app01_book where(NOT (`app01_book`.`title` = 三国演义) OR `app01_book`.`number` = 1000)

Q的高阶用法

需求: 我们使用filter()传入的参数都必须是手动输入已经存在的, 那么如何将输入筛选条件写的灵活呢?

condition = input('请输入你要筛选的条件:')
data = input('请输入你要筛选的值:')
res = Book.objects.filter(condition = data)

很明显,这样写是不行的, 因为book表中并没有condition字段,所以会报错,可以借助Q对象来实现

condition = input('请输入你要筛选的条件:')
data = input('请输入你要筛选的值:')
q = Q()
q.children.append((condition,data))
res = Book.objects.filter(q)
print(res.query)

# condition = title
# data = 三国演义
# SELECT * FROM `app01_book` WHERE `app01_book`.`title` = 三国演义

也可以多次添加条件,并且修改链接多个条件的方法, 默认是AND

q = Q()
q.children.append(("title","三国演义"))
q.children.append(("nuber__gt","500"))
res = Book.objects.filter(q)
print(res.query)

# SELECT * FROM `app01_book` WHERE (`app01_book`.`title` = 三国演义 AND `app01_book`.`number` > 500)


q = Q()
q.connector='or'
q.children.append(("title","三国演义"))
q.children.append(("nuber__gt","500"))
res = Book.objects.filter(q)
print(res.query)
# SELECT * FROM `app01_book` WHERE (`app01_book`.`title` = 三国演义 OR `app01_book`.`number` > 500)

聚合查询

内置函数导入

from django.db.models import Avg,Sum.Max,Min,Count()

关键字: aggregate('筛选的字段名')

最终返回的是一个字典类型的数据

求书籍的总价和最高价

from django.db.models import *
res = Book.objects.aggregate(Max('price'),Sum('price'))
print(res)

# {'price__max': Decimal('300.50'), 'price__sum': Decimal('1366.83')}

分组查询

单表分组查询与跨表分组查询中聚合函数括号内传入的值是不一样的!!

单表分组查询

关键字: annotate(annotate(聚合字段别名=聚合函数('表内')).values('字段1','聚合字段别名)

from django.db.models import Avg
Employee.objects.values("dept").annotate(avg=Avg("salary").values("dept", "avg")
                                         
"""
这里需要注意的是annotate分组依据就是他前面的值,
如果前面没有特点的字段,则默认按照ID分组,
这里有dept字段,所以按照dept字段分组
"""

多表分组查询

关键字:annotate(聚合字段别名=聚合函数('正反向查询规则')).values('字段1','聚合字段别名')

from django.db.models import Avg
models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")

总结

value里边的参数对应的是sql语句中的select要查找显示的字段

filter里边的参数相当于where或者having里边的筛选条件

annotate本身表示group by 的作用. 前面找寻分组依据, 内部放置显示可能用到的聚合运算式,后面跟filter来增加限制条件,最后的value来表示分组后想要查找的字段值

ORM查询优化

only 与 defer

Django ORM默认是惰性查询,当ORM语句在后续的代码中真正需要使用的时候才会执行。

如果你明确不需要这个数据库列(或在大部分情况里不需要),使用 defer() 和 only() 来避免加载它们.

obj = models.Book.objects.only('title', 'price')
for i in obj:
    print(i.title)
    print(i.price)
    print(i.sale

only会查询括号内的字段并封装成一个对象返回,使用该对象不会在通过数据库查询。但是查询括号里没有的字段,还是会走数据库。

obj = models.Book.objects.defer('title', 'price')
for i in obj:
	print(i.title)
	print(i.price)
	print(i.sale)

而defer和only相反。

select_related 和 prefetch_related

select_related()

select_related(*fileds)

返回一个QuerySet, 他将跟随外键关系, 再执行查询时选择额外的相关对象数据, 这是一个性能升器, 他导致一个更复杂的单一查询, 意味着以后使用外键关系将不需要数据库查询.

b = models.Book.objects.select_related('publish')     # 拼表
for i in b:
    print(i.title)
    print(i.price)
    print(i.sale)

c = models.Author.objects.select_related('author_info')
print(c)    # 只支持一对一和一对多关系

prefetch_related()

prefetch_related(*lookups)

返回一个QuerySet, 他将在一个批次中自动检索每个指定查询的相关对象

这与select_related有类似的目的, 二者都是为了阻止因访问相关对象而引起的数据库查询潮,但策略却完全不同

select_related 的工作方式是创建一个SQL链接, 并在SELECT语句中包含相关对象的字段, 处于这个原因,select_related在同一个数据据库查询中得到相关对象. 然而为了避免因跨越'many'关系进行链接而产生更大的结果集, select_related仅限于单值关系>>>>外键和一对一.

prefetch_related则对每个关系进行单独的查找, 并在python中进行joining. 这使得它除了支持select_related的外键和一对一关系, 还可以预约多对多和多对一的对象, 这是用select_Related无法做到.

https://docs.djangoproject.com/zh-hans/4.1/ref/models/querysets/#django.db.models.query.QuerySet.select_related

事务操作

django默认的事务行为是自动提交, 触发事务正在执行, 每个查询将会马上自动提交到数据库.

django自动使用事务或还原点,以确保需要多次查询的ORM操作的一致性, 特别是delete() 和 update()操作. 

官方文档:数据库事务 | Django 文档 | Djangohttps://docs.djangoproject.com/zh-hans/4.1/topics/db/transactions/#deactivating-transaction-management

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Django-ORM 单表查询 的相关文章

随机推荐

  • python遍历指定目录并打印层级结构

    import os def func filepath n 获取路径 files os listdir filepath for file in files 拼接路径 f d os path join filepath file 判断路径是
  • STM32CubeMX安装与使用

    STM32CubeMX 是 ST 公司近几年来大力推荐的STM32 芯片图形化配置工具 允许用户使用图形化向导生成C 初始化代码 支持多种工具链 比如MDK IAR TrueStudio等 可以大大减轻开发工作时间 提高开发效率 STM32
  • C++ Primer Plus 书之--C++ 模板类深究2--模板类和友元

    模板类和友元 模板类声明也可以有友元 模板的友元分为3类 1 非模板友元 2 约束模板友元 即友元的类型取决于类被实例化时的类型 3 非约束模板友元 即友元的所有具体化都是类的每一个具体化的友元 1 模板类的非模板友元函数 在模板类中将一个
  • 创建型模式,共五种

    设计模式 Design Patterns 可复用面向对象软件的基础 设计模式 Design pattern 是一套被反复使用 多数人知晓的 经过分类编目的 代码设计经验的总结 使用设计模式是为了可重用代码 让代码更容易被他人理解 保证代码可
  • scikit-image 0.17.2计算PSNR、SSIM、MSE

    版本及调用方式 scikit image 0 18 0之前版本的调用方式如下 from skimage measure import compare mse compare psnr compare ssim scikit image 0
  • 数字逻辑练习题(五) 分析下图所示组合逻辑电路的功能

    分析下图所示组合逻辑电路的功能 一 题目描述 分析下图所示组合逻辑电路的功能 要求 1 写出该电路输出 L1 L2 L3 的逻辑函数表达式 2 列出真值表 3 描述该电路的功能 二 题目解答 1 列出逻辑表达式 2 列出真值表 3 电路功能
  • 开发工程中遇到的BUG

    1 Couldn t communicate with a helper application in Xcode 7 问题一 Couldn t communicate with a helper application in Xcode
  • CMake Tutorial Step1

    CMake Tutorial Step1 参考资料 Step 1 A Basic Starting Point CMake 3 26 3 Documentation Tutorial工程 官方Tutorial工程 开发环境 CLion CM
  • 数据库/MySQL - 深入探究 - 1

    1 应用场景 主要用于了解和掌握数据库 MySQL 更新操作详细流程 2 学习 操作 1 文档阅读 主要来自于AI的对话 geek chat chatgpt 以及官方文档资料 以及其他技术文章 专栏等 2 整理输出 抛出问题 数据库 这里以
  • Jenkins部署

    链接 手把手教你用 Jenkins 自动部署 SpringBoot 江南一点雨 jekins 江南一点雨的博客 CSDN博客 bin bash jenkins要在后台执行脚本 需要在脚本前加上BUILD ID dontKillMe BUIL
  • Python while循环结构

    视频版教程 Python3零基础7天入门实战视频教程 循环语句可以在满足循环条件的情况下 反复执行某一段代码 这段被重复执行的代码被称为循环体 当反复执行这个循环体时 需要在合适的时候把循环条件改为假 从而结束循环 否则循环将一直执行下去
  • pycharm语句用法

    Python介绍 Python 是一个高层次的结合了解释性 编译性 互动性和面向对象的脚本语言 Python 的设计具有很强的可读性 相比其他语言经常使用英文关键字 其他语言的一些标点符号 它具有比其他语言更有特色语法结构 Python 是
  • 多种JS代码混淆加密,效果一览。

    演示代码如下 用JShaman对这段代码进行混淆加密 function demo alert hello www jshaman com demo 一 通用版 1 配置选项 压缩代码 保护效果 function demo alert hel
  • SQL数据库的连接、创建操作

    目录 1 数据库的连接 创建 2 对字段的操作 alter table 3 对数据的操作 插入 修改 删除 4 数据查询 select 5 多表查询 join on 6 约束操作 一 数据库的连接 创建 1 连接root数据库 cmd中输入
  • Python爬虫从入门到精通:(8)数据解析_xpath解析基础_Python涛哥

    xpath解析基础 环境安装 pip install lxml 解析原理 html标签是以树状的形式进行展示 实例化一个etree对象 且将待解析的页面源码数据加载到该对象中 调用etree对象的xpath方法结合着不同的xpath表达式实
  • 写了一个 SSO 单点登录的代码示例给胖友!

    发危 摘要 原创出处 http www iocoder cn Spring Security OAuth2 learning sso 芋道源码 欢迎转载 保留摘要 谢谢 1 概述 2 搭建统一登录系统 3 搭建 XXX 系统 666 彩蛋
  • js正则表达式多行匹配

    在js匹配网页内容时 往往需要匹配一段代码比如 div div 中间可能有很多行 这个时候一般 的匹配规则是匹配不出来的 如下介绍一个折中的方法 var content 这里是内容 var re p class s S p gt g var
  • win10微软应用商店不能用?简单两步完美解决

    想安装微软的软件 发现微软应用商店打不开 无论是我刷新还是重启 找了各种办法终于解决了 解决办法 1 打开键盘 田 R 键 输入 inetcpl cpl 2 然后去高级那里打开 勾上 使用TLS 1 2 选项 或者还原高级设置 3 最后打开
  • javaweb前后台交互传递数据的几种方法

    前端传后台 form表单传递
  • Django-ORM 单表查询

    目录 数据准备 查询关键字 1 QuerySet 对象 first方法 last方法 values方法 values list 方法 count exists 2 all 3 filter kwargs 4 get kwargs 不推荐使用