聚合与分组查询、F与Q查询
目录图书管理系统
# 表设计
先考虑普通字段再考虑外键字段,之后再做数据库迁移及测试数据录入。
# 首页展示
# 书籍展示
# 书籍编辑
主要针对后端怎样获取用户想要编辑的数据,前端怎样展示待编辑的数据。
# 书籍删除
聚合查询
在ORM中支持单独使用聚合函数,需要使用aggregate方法。
聚合函数:
Max(最大)、Min(最小)、Sum(总和)、Avg(平均)、count(统计)
# 示例1:
from django.db.models import Max, Min, Sum, Count, Avg
res = models.Book.objects.aggregate(Max('price'), Count('pk'), 最小价格=Min('price'), allPrice=Sum('price'),平均价格=Avg('price'))
print(res)
"""
在进行聚合查询时,可以给聚合查询的内容命名,若不主动命名,也会自动用下划线拼接两个字段名,但命名不建议使用中文(虽然可以用)
"""
# 示例2:
from django.db.models import Max, Min, Sum, Avg, Count
1.查找所有书籍中价格最高的书籍
res = models.Book.objects.aggregate(我是世界上最贵的书=Max('price'))
print(res)
# 没有分组之前如果单纯的时候聚合函数,需要关键字aggregate
2.获取书籍中最贵的、最便宜的、全部需要多少钱、平均一本书多少钱、总共有几本书
res1 = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Avg('price'), Count('pk'))
print(res1)
'''通过 别名 = 聚合函数的方法可以取一个别名'''
分组查询
注意:
若执行orm分组查询报错,并且有关键字sql_mode,需要去mysql配置文件中修改严格模式的配置信息。(Mac不会有)
strict mode
移除sql_mode中的only_full_group_by
# 分组查询
from django.db.models import Max, Min, Sum, Count, Avg
# 统计每一本书的作者个数
res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('title', 'author_num')
print(res)
# 统计出每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
print(res)
# 统计不止一个作者的图书
# 1.先统计每本书的作者个数
res = models.Book.objects.annotate(author_num=Count('authors__pk'))
print(res)
# 2.筛选出作者个数大于1的数据
res = models.Book.objects.annotate(author_num=Count('authors__pk')).filter(author_num__gt=1).values('title','author_num')
print(res)
# 查询每个作者出的书的总价格
"""
按照表分组
models.表名.objects.annotate()
按照values括号内指定的字段分组
models.表名.objects.values('字段名').annotate()
"""
res = models.Author.objects.annotate(总价=Sum('book__price'), count_book=Count('book__pk')).values('name','总价','count_book')
print(res)
res = models.Book.objects.values('publish_id').annotate(count_pk=Count('pk')).values('publish_id', 'count_pk')
print(res)
ORM如何给表再次添加新的字段
在对数据库使用ORM进行操作的时候,若出现需要新增字段的情况。可以在模型层修改了代码之后、进行数据迁移操作之前,对新增的字段值进行设置,否则不让进行数据库迁移。
可以将字段值设置成一个固定的值,也可以设置字段值可为空。
# 代码展示
首先给书籍表格再添加两条数据(库存及已销售)
storage_num = models.IntegerField(verbose_name='库存数')
sale_num = models.IntegerField(verbose_name='已销售')
# 出现报错信息:
we can't do that (the database needs something to populate existing rows)
现在这张表已经有数据了,再添加两个新的字段。
没有数据值,它的数据值呢?
两种方式:
一个默认值,一个退出不执行这个命令再去修改(所以需要给这两个字段加上数据)
storage_num = models.IntegerField(verbose_name='库存数', null=True)
sale_num = models.IntegerField(verbose_name='已销售', default=1000)
F与Q查询
导入模块
from django.db.models import F,Q
# F查询
能够直接获取到列表中某个字段对应的数据
注意:
在操作字符串类型的数据时,F不能够直接做到字符串的拼接
# 查询卖出书大于库存数的书籍
res = models.Book.objects.filter(storage_num__gt=F('sale_num'))
print(res)
# 将所有书籍的价格上涨1000圆子
res = models.Book.objects.update(price=F('price') + 1000)
# 给所有书籍名称后面加上爆款后缀
针对字符串数据无法直接拼接
models.Book.objects.filter().all().update(title=F('title') + '爆款')
# 导入Concat模块
from django.db.models.functions import Concat
# 导入Value模块
from django.db.models import Value
models.Book.objects.filter().all().update(title=Concat(F('title'), Value('~爆款')))
# Q查询
可改变filter括号内多个条件之间的逻辑运算符,还可以将查询的结果改为字符串形式。
filter()等方法中的关键字参数查询都是一起进行"and",如果需要执行更复杂的查询(例如ORM语句),可使用Q对象。
# 查询卖出数大于100并且价格小于60的书籍
res = models.Book.objects.filter(Q(sale_num__gt=100), Q(price__lt=600))
print(res)
# 查询卖出数大于130或者价格小于30的书籍
res = models.Book.objects.filter(Q(sale_num__gt=130) | Q(price__lt=30))
print(res)
# 查询卖出数不是大于80或者价格大于600的书籍
res = models.Book.objects.filter(~Q(sale_num__gt=80) | Q(price__gt=600))
print(res)
# 结论
, and关系
| or关系
~ not关系
Q 默认是and,可以进行修改
q = Q()
q.connector = 'or'
# Q查询进阶用法
可将查询结果改为字符串形式
先产生一个对象
q = Q()
修改默认的对象
q.connector = 'or'
添加查询条件,第一个写一个字符串的字段名 第二个元素写一些具体的数值
q.children.append(('pk', 1))
q.children.append(('publish_id', 3))
添加好以后q对象支持直接用filter进行筛选
res = models.Book.objects.filter(q)
print(res)
标签:聚合,models,res,price,num,查询,objects,分组
From: https://www.cnblogs.com/zhiliaowang/p/17020186.html