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

Django-ORM 单表查询

数据准备

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来表示分组后想要查找的字段值

相关文章:

  • 基础数据结构详解
  • 淘宝天猫店铺商品API,店铺商品分类接口代码对接教程
  • 神器 SpringDoc 横空出世!最适合 SpringBoot 的API文档工具来了
  • 剑指offer68-77二分查找、排序
  • vue filters过滤器分别在template和script中使用
  • ssm毕设项目基于Java的城市公交查询系统ac5p2(java+VUE+Mybatis+Maven+Mysql+sprnig)
  • unity sdk -AppLovin MAX 广告聚合平台接入+Firebase统计
  • C#手动填充DataSet
  • coreutils5.0 uname命令和源码分析
  • OpenGL入门(四)之纹理Texture
  • UDP和TCP协议发送接收数据
  • Apache Doris 快速学习大纲
  • FastFlow(5)---软件加速器 software accelerator
  • 华为OD:0019-0020:-最小步骤数—删除字符串中出现次数最少的字符
  • Python学生成绩管信息理系统(面向对象)(学生信息篇)
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • avalon2.2的VM生成过程
  • Essential Studio for ASP.NET Web Forms 2017 v2,新增自定义树形网格工具栏
  • flask接收请求并推入栈
  • httpie使用详解
  • Java 网络编程(2):UDP 的使用
  • javascript 总结(常用工具类的封装)
  • Java应用性能调优
  • mysql 5.6 原生Online DDL解析
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • oldjun 检测网站的经验
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • React16时代,该用什么姿势写 React ?
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • Spring思维导图,让Spring不再难懂(mvc篇)
  • Vue 动态创建 component
  • vue-router 实现分析
  • 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • 手机端车牌号码键盘的vue组件
  • 在electron中实现跨域请求,无需更改服务器端设置
  • 看到一个关于网页设计的文章分享过来!大家看看!
  • FaaS 的简单实践
  • RDS-Mysql 物理备份恢复到本地数据库上
  • ​​​​​​​​​​​​​​Γ函数
  • !!Dom4j 学习笔记
  • (Python) SOAP Web Service (HTTP POST)
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (区间dp) (经典例题) 石子合并
  • (十八)三元表达式和列表解析
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .NET 跨平台图形库 SkiaSharp 基础应用
  • .NET 指南:抽象化实现的基类
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • .NET/C# 使用反射注册事件
  • @data注解_一枚 架构师 也不会用的Lombok注解,相见恨晚