聚合查询和分组查询

聚合

aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。

示例:

>>> models.Book.objects.all().aggregate(Avg("price"))
{'price__avg': 13.233333}

如果你想要为聚合值指定一个名称,可以向聚合子句提供它。

>>> models.Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 13.233333}

如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:

>>> models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
{'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}

分组

为调用的QuerySet中每一个对象都生成一个独立的统计值

示例1:统计每一本书的作者个数

 
>>> book_list = models.Book.objects.all().annotate(author_num=Count("author"))
>>> for obj in book_list:
... print(obj.author_num)
...
2
1
1
 

示例2:统计出每个出版社买的最便宜的书的价格

 
>>> publisher_list = models.Publisher.objects.annotate(min_price=Min("book__price"))
>>> for obj in publisher_list:
... print(obj.min_price)
...
9.90
19.90
 

方法二:

>>> models.Book.objects.values("publisher__name").annotate(min_price=Min("price"))
<QuerySet [{'publisher__name': '沙河出版社', 'min_price': Decimal('9.90')}, {'publisher__name': '人民出版社', 'min_price': Decimal('19.90')}]>

示例3:统计不止一个作者的图书

>>> models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1)
<QuerySet [<Book: 番茄物语>]>

示例4:根据一本图书作者数量的多少对查询集 QuerySet进行排序

>>> models.Book.objects.annotate(author_num=Count("author")).order_by("author_num")
<QuerySet [<Book: 香蕉物语>, <Book: 橘子物语>, <Book: 番茄物语>]>

示例5:查询各个作者出的书的总价格

>>> models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price")
<QuerySet [{'name': '小精灵', 'sum_price': Decimal('9.90')}, {'name': '小仙女', 'sum_price': Decimal('29.80')}, {'name': '小魔女', 'sum_price': Decimal('9.90')}]>

F查询和Q查询

F查询

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

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

示例1:

查询评论数大于收藏数的书籍

from django.db.models import F
models.Book.objects.filter(commnet_num__lt=F('keep_num'))

Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。

models.Book.objects.filter(commnet_num__lt=F('keep_num')*2)

修改操作也可以使用F函数,比如将每一本书的价格提高30元

models.Book.objects.all().update(price=F("price")+30)

引申:

如果要修改char字段咋办?

如:把所有书名后面加上(第一版)

 
>>> from django.db.models.functions import Concat
>>> from django.db.models import Value
>>> models.Book.objects.all().update(title=Concat(F("title"), Value("("), Value("第一版"), Value(")")))
 

Q查询

filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象。

示例1:

查询作者名是小仙女或小魔女的

models.Book.objects.filter(Q(authors__name="小仙女")|Q(authors__name="小魔女"))

你可以组合& 和|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询。

示例:查询作者名字是小仙女并且不是2018年出版的书的书名。

>>> models.Book.objects.filter(Q(author__name="小仙女") & ~Q(publish_date__year=2018)).values_list("title")
<QuerySet [('番茄物语',)]>

查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。

例如:查询出版年份是2017或2018,书名中带物语的所有书。

>>> models.Book.objects.filter(Q(publish_date__year=2018) | Q(publish_date__year=2017), title__icontains="物语")
<QuerySet [<Book: 番茄物语>, <Book: 香蕉物语>, <Book: 橘子物语>]>

1 关于聚合aggregate 

它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。

from django.db.models import Avg,Max,Min,Sum

models.Book.objects.aggregate(Avg('price'))
(0.001) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.092) SELECT AVG(`app02_book`.`price`) AS `price__avg` FROM `app02_book`; args=()

{'price__avg': 19.7725}

models.Book.objects.aggregate(ping_jun=Avg('price'))
{'ping_jun': 19.7725}

(0.001) SELECT AVG(`app02_book`.`price`) AS `ping_jun` FROM `app02_book`; args=()


models.Book.objects.aggregate(zuida=Max('price'))
{'zuida': Decimal('29.90')}


(0.093) SELECT MAX(`app02_book`.`price`) AS `zuida` FROM `app02_book`; args=()

odels.Book.objects.aggregate(Max('price'),Avg('price'),Min('price'))
{'price__max': Decimal('29.90'), 'price__avg': 19.7725, 'price__min': Decimal('9.99')}

(0.002) SELECT MAX(`app02_book`.`price`) AS `price__max`, AVG(`app02_book`.`price`) AS `price__avg`, MIN(`app02_book`.`price`) AS `price__min` FROM `app02_book`; args=()

关于 分组 annotate调用的QuerySet中每一个对象都生成一个独立的统计值

from django.db.models import Count
a = models.Author.objects.annotate(sum=Count('books__title'))

for i in a:
print(i.name,i.sum)

(0.062) SELECT `app02_author`.`id`, `app02_author`.`name`, `app02_author`.`detail_id`, COUNT(`app02_book`.`title`) AS `sum` FROM `app02_author` LEFT OUTER JOIN `app02_author_books` ON (`app02_author`.`id` = `app02_author_books`.`author_id`) LEFT OUTER JOIN `app02_book` ON (`app02_author_books`.`book_id` = `app02_book`.`id`) GROUP BY `app02_author`.`id` ORDER BY NULL; args=()
王小一 2
张小二 1
李小三 1
赵小四 0

b = models.Author.objects.annotate(avg_price=Avg('books__price'))

(0.035) SELECT `app02_author`.`id`, `app02_author`.`name`, `app02_author`.`detail_id`, AVG(`app02_book`.`price`) AS `avg_price` FROM `app02_author` LEFT OUTER JOIN `app02_author_books` ON (`app02_author`.`id` = `app02_author_books`.`author_id`) LEFT OUTER JOIN `app02_book` ON (`app02_author_books`.`book_id` = `app02_book`.`id`) GROUP BY `app02_author`.`id` ORDER BY NULL LIMIT 21; args=()
for i in b :
print(i.name,i.acg_price)

(0.002) SELECT `app02_author`.`id`, `app02_author`.`name`, `app02_author`.`detail_id`, AVG(`app02_book`.`price`) AS `avg_price` FROM `app02_author` LEFT OUTER JOIN `app02_author_books` ON (`app02_author`.`id` = `app02_author_books`.`author_id`) LEFT OUTER JOIN `app02_book` ON (`app02_author_books`.`book_id` = `app02_book`.`id`) GROUP BY `app02_author`.`id` ORDER BY NULL; args=()
Traceback (most recent call last):
for i in b :
print(i.name,i.avg_price)

王小一 24.95
张小二 20.0
李小三 29.9
赵小四 None

关于F 和Q 查询
1新建一个app04
D:\py文件存放\Book>python manage.py startapp app04
2在django 项目settings 进行设置
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app02.apps.App02Config',
'app03.apps.App03Config',
'app04.apps.App04Config',
]

对数据库的修改 对app04 进行登记 和执行

关于 同字段F 的查询
在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?

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

from app04 import models
from django.db.models import F
models.Goods.objects.filter(keep_num__gt=F('buy_num'))
(0.001) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.001) SELECT VERSION(); args=None
<QuerySet [<Goods: 大萝卜>]>
(0.001) SELECT `app04_goods`.`id`, `app04_goods`.`name`, `app04_goods`.`keep_num`, `app04_goods`.`buy_num` FROM `app04_goods` WHERE `app04_goods`.`keep_num` > (`app04_goods`.`buy_num`) LIMIT 21; args=()
(0.001) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.000) SELECT VERSION(); args=None
(0.001) SELECT `app04_goods`.`id`, `app04_goods`.`name`, `app04_goods`.`keep_num`, `app04_goods`.`buy_num` FROM `app04_goods` WHERE `app04_goods`.`keep_num` > (`app04_goods`.`buy_num`) LIMIT 21; args=()

models.Goods.objects.filter(keep_num__gt=F('buy_num')*2)
<QuerySet [<Goods: 大萝卜>]>
(0.076) SELECT `app04_goods`.`id`, `app04_goods`.`name`, `app04_goods`.`keep_num`, `app04_goods`.`buy_num` FROM `app04_goods` WHERE `app04_goods`.`keep_num` > ((`app04_goods`.`buy_num` * 2)) LIMIT 21; args=(2,)
(0.001) SELECT `app04_goods`.`id`, `app04_goods`.`name`, `app04_goods`.`keep_num`, `app04_goods`.`buy_num` FROM `app04_goods` WHERE `app04_goods`.`keep_num` > ((`app04_goods`.`buy_num` * 2)) LIMIT 21; args=(2,)

models.Goods.objects.all().update(buy_num=F('buy_num')+1000)
(0.084) UPDATE `app04_goods` SET `buy_num` = (`app04_goods`.`buy_num` + 1000); args=(1000,)
4

拼接 字符串
from django.db.models import Value
from django.db.models.functions import Concat

models.Goods.objects.all().update(name=Concat(Value('特价'),F(name)))

支持多个参数
models.Goods.objects.all().update(name=Concat(Value('('),Value('特价'),Value(')'),F('name')))

关于Q查询(就是or| 和and &) 联表查询 跨表字段前面需要加上杠杠

filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象。

或者 or 的意思

models.Author.objects.filter(Q(name='王小一')|Q(name='张小二'))
(0.063) SELECT `app02_author`.`id`, `app02_author`.`name`, `app02_author`.`detail_id` FROM `app02_author` WHERE (`app02_author`.`name` = '王小一' OR `app02_author`.`name` = '张小二') LIMIT 21; args=('王小一', '张小二')
<QuerySet [<Author: 王小一>, <Author: 张小二>]>

并且的意思

models.Book.objects.filter(Q(author__name='王小一')&Q(publish_day__year='2017'))
(0.002) SELECT `app02_book`.`id`, `app02_book`.`title`, `app02_book`.`price`, `app02_book`.`publish_day`, `app02_book`.`publisher_id`, `app02_book`.`memo` FROM `app02_book` INNER JOIN `app02_author_books` ON (`app02_book`.`id` = `app02_author_books`.`book_id`) INNER JOIN `app02_author` ON (`app02_author_books`.`author_id` = `app02_author`.`id`) WHERE (`app02_author`.`name` = '王小一' AND `app02_book`.`publish_day` BETWEEN '2017-01-01' AND '2017-12-31') LIMIT 21; args=('王小一', '2017-01-01', '2017-12-31')
<QuerySet [<Book: 芥末物语>]>

70 多表查询的分组F 聚合 Q 查询的更多相关文章

  1. Django 聚合分组F与Q查询及choices

    一.聚合查询 需要导入模块:from django.db.models import Max, Min, Sum, Count, Avg 关键语法:aggregate(聚合结果别名 = 聚合函数(参数 ...

  2. django----聚合查询 分组 F与Q查询 字段 及其 参数

    目录 一.orm补充查询 聚合查询 1-1 分组查询 1-2 F与Q查询 1-3 二. 字段及其参数 常用字段 AutoField IntegerField CharField DateField D ...

  3. Django 08 Django模型基础3(关系表的数据操作、表关联对象的访问、多表查询、聚合、分组、F、Q查询)

    Django 08 Django模型基础3(关系表的数据操作.表关联对象的访问.多表查询.聚合.分组.F.Q查询) 一.关系表的数据操作 #为了能方便学习,我们进入项目的idle中去执行我们的操作,通 ...

  4. Django 聚合查询 分组查询 F与Q查询

    一.聚合查询 需要导入模块:from django.db.models import Max, Min, Sum, Count, Avg 关键语法:aggregate(聚合结果别名 = 聚合函数(参数 ...

  5. Django中多表的增删改查操作及聚合查询、F、Q查询

    一.创建表 创建四个表:书籍,出版社,作者,作者详细信息 四个表之间关系:书籍和作者多对多,作者和作者详细信息一对一,出版社和书籍一对多 创建一对一的关系:OneToOne("要绑定关系的表 ...

  6. django基础之day05,F与Q查询,Q查询的高级用法

    #F与Q查询 #*************************** F 查询 ******************** # F 查询数据库中的其他字段!!! #1.查询库存数大于卖出数的书籍 fr ...

  7. F与Q查询 事务 choices参数

    F与Q查询 F查询 当我们需要将两个字段对应的数据进行比较时就需要用到F查询. select * from book where sold > stock 1.例如需要将售出部分数据和库存数据进 ...

  8. django F与Q查询 事务 only与defer

    F与Q 查询 class Product(models.Model): name = models.CharField(max_length=32) #都是类实例化出来的对象 price = mode ...

  9. Django ORM 之F、Q查询与事务

    返回ORM目录 Django ORM 内容目录 一.F.Q查询 二.事务 三.only与defer 一.F.Q查询 """ Product表中的数据: 1 橡皮 2 20 ...

随机推荐

  1. C# 有哪些集合

    队列[Queue] //队列:先进先出 /* *增加元素到队列结尾处 *移除队列开始处 */ Queue queue=new Queue(); queue.Enqueue(Object); queue ...

  2. 6月5 Smarty变量调节器

    变量调节器:<{$a|变量调节器}> 主要修改此页面的信息来了解变量调节器:test0605/main.php和模板文件:main0605.html 1.利用给定的变量调节器 capita ...

  3. java解析前端请求接口的全部入参

    第一种: public static String getRequestInput(HttpServletRequest request) { StringBuilder sb = new Strin ...

  4. 自定义alert弹框,title不显示域名

    问题: 系统默认的alert弹框的title会默认显示网页域名 解决办法: (修改弹框样式) (function() { window.alert = function(name) { $(" ...

  5. python-flask-路由匹配源码分析

    @app.route('/') def hello_world(): return 'Hello World!' 第1步: class Flask(_PackageBoundObject): def ...

  6. PyCharm + PyQt4 环境搭建

    一.准备工作 下载pycharm 和 pyqt4 (百度下就有) pyqt4安装好后,在C:\Python27\Lib\site-packages\PyQt4 路径下会有designer.exe ,这 ...

  7. 数据结构与算法之PHP用邻接表、邻接矩阵实现图的广度优先遍历(BFS)

    一.基本思想 1)从图中的某个顶点V出发访问并记录: 2)依次访问V的所有邻接顶点: 3)分别从这些邻接点出发,依次访问它们的未被访问过的邻接点,直到图中所有已被访问过的顶点的邻接点都被访问到. 4) ...

  8. java旅程(二) 基本语法

    java变量: 数值型        整数类型(byte,short,int,long)浮点类型(float,double) 字符型 char 基本数据类型                       ...

  9. Oracle Log Block Size

    Although the size of redo entries is measured in bytes, LGWR writes the redo to the log files on dis ...

  10. WebSphere隐藏版本号教程

    一.实施步骤 1.登陆WAS控制台,进入服务器列表界面. 2.选择一个server进到server配置页面. 3.选择进入“Web容器传输链”页面. 针对这4项都进行以下第4和第5步操作,以下以WCI ...