Django 中的aggregate、annotate以及Q、F查询
日常工作使用中,大部分的条件查询通过filter
都可以完成,但是在更复杂的查询时,filter
就显得无力了。
不过,好在Django为我们提供了一些可以进行复杂查询的语句,比如aggregate, annotate, Q, F
models
来自Django官方文档的
models
,本文的查询都基于这些models
1 | from django.db import models |
aggregate(聚合查询)
在原生SQL语句中常常会用到一些聚合函数,用来对一组数据进行计算,比如AVG/COUNT/MAX/MIN/SUM
等, aggregate
则是Django
中实现聚合函数的。以下用几个简单例子来说明。
例:求某个出版社出售的最便宜的一本书
1 | from django.db.models import MIN |
aggregate 后的结果不再为QuerySet, 而是相应的{min_price=20.00}, 如果未设置字段名,会默认为
查询字段__聚合方法
,例如price__min
当然如何你想聚合其他值,比如平均价格或者最高评分,可以添加参数
1 | from django.db.models import Avg, Max, Min |
annotate(分组查询)
annotate
,顾名思义就是为QuerySet
中的每个对象生成一个独立的统计值, 统计值会存在QuerySet
。
例:统计每个出版社出版的图书数量,并且以倒序排列
1 | from django.db.models import Count |
通过 pubs[0].book_num 来查看结果
例:查询每个出版社出的书的总价格
1 | from django.db.models import Sum |
Q查询
filter()
等方法中的关键字参数查询 都是进行AND
运算,如果需要执行类型OR
语句,就需要使用Q查询
了。
当多个条件查询时,还可以通过&
, |
以及()
进行分组编写Q对象,而且Q对象还可以通过使用 ~
表达取反(NOT),当然如果查询较简单也可以使用exclude。
例:查询价格是小于20或大于50的图书
1 | from django.db.models import Q |
例:查询出版社是新华出版社或者清华出版社并且不是2018年出版的书
1 | from django.db.models import Q |
如果想Q查询
与关键字参数同时使用,需要遵循一个条件,Q对象必须位于所有关键字参数前面,如下所示
例:查询新华出版社评分在5-9之间的图书
1 | from django.db.models import Q |
F查询
在上面的例子中,我们只是将字段值与某个常量作比较进行筛选,如果需要对字段值之间比较筛选,就需要使用Django 提供的F查询
。
例:查询会员价与原价相同的图书
1 | from django.db.models import F |
当然F语句
还可以更改一列值,例如将选中的所有图书原价增加10块
1 | Book.objects.all().update(price=F('price')+10) |
与annotate
查询一起使用,求原价与会员价的差价
1 | from django.db.models import F |
总结
这4种查询已经可以应付大多数的场景,对不同的场景可以有不同的组合方式,在我看来:
aggregate
用于聚合统计数据;annotate
用于对数据进行分组,类似group by
;Q()
是对QuerySet
进行更复杂的过滤筛选;F()
用于对Query
字段间的某列值进行比较或操作。
本文只是简单的介绍了4种查询,更多内容可查阅Django官方文档