Django model 层之聚合查询总结
Django model 层之聚合查询总结
by:授客 QQ:1033553122
实践环境
Python版本:python-3.4.0.amd64
下载地址:https://www.python.org/downloads/release/python-340/
Win7 64位
Django 1.11.4
下载地址:https://www.djangoproject.com/download/
聚合查询
MySQL数据库为例,假设项目目录结构如下:
mysite/
myapp/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
models.py内容如下:
from django.db import models
# Create your models
here.
class
Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class Book(models.Model):
book_name = models.CharField(max_length=30)
borrower = models.ForeignKey(Person,
to_field='id', on_delete=models.CASCADE)
class
Store(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50)
last_update =
models.DateField(auto_now=True)
class
Production_addr(models.Model):
addr = models.CharField(max_length=50)
distance = models.IntegerField()
class
Fruit(models.Model):
store = models.ManyToManyField(Store)
production_addr =
models.ForeignKey(Production_addr, to_field='id', on_delete=models.CASCADE)
name = models.CharField(max_length=100)
onsale_date = models.DateField()
price = models.IntegerField()
class
Taste(models.Model):
taste = models.CharField(max_length=50)
fruit=models.ManyToManyField(Fruit)
class
News(models.Model):
title = models.CharField(max_length=20)
n_comments = models.IntegerField()
n_pingbacks = models.IntegerField()
rank = models.IntegerField()
class Blog(Book):
author = models.CharField(max_length=50)
针对整个QuerySet生成聚合
例:查询myapp_news表中,rank值大于26的记录,其n_comments平均值
>>> from myapp.models import News
>>> from django.db.models
import Avg
>>>
News.objects.filter(rank__gt=26).aggregate(Avg('n_comments'))
{'n_comments__avg': 17.0}
如果是针对所有记录求均值,我们可以这样
>>>
News.objects.all().aggregate(Avg('n_comments'))
{'n_comments__avg': 23.0}
也可以去掉all()
>>>
News.objects.aggregate(Avg('n_comments'))
{'n_comments__avg': 23.0}
返回结果说明
{'聚合结果值标识':'聚合结果值'}
自定义聚合结果标识
>>> News.objects.all().aggregate(average_price
= Avg('n_comments'))
{'average_price': 23.0}
>>> from django.db.models
import Avg, Max, Min
>>>
News.objects.aggregate(Avg('n_comments'), Max('n_comments'), Min('n_comments'))
{'n_comments__max': 35, 'n_comments__min': 14,
'n_comments__avg': 23.0}
针对整个QuerySet的每项生成聚合
可以理解为mysql中的分组统计,Model.objects.annotate(……) ,不过不一样的是,这里没有指定分组字段,是按每个model对象分组。
例子:Fruit和Store model存在多对多关系。现在需要查询,myapp_fruit表中某条记录(可以理解为每类水果),有多少家商店在出(myapp_store表中每条记录对应一个商店)
>>> from myapp.models import Fruit,
Production_addr, Store, Taste
>>> from django.db.models
import Count
>>> q =
Fruit.objects.annotate(Count('store'))
>>> q[0]
<Fruit: Fruit object>
>>> q[0].store__count
1
>>> q[1].store__count
3
>>> q[2].store__count
1
默认的,annotation标识由aggregate函数及被聚合field而来(例中为store__count),类似aggregate, 可以自定义annotation标识
>>> q =
Fruit.objects.annotate(store_num = Count('store'))
>>> q[0].store_num
1
>>>
和aggregate不同的是,annotate()语句输出结果为QuerySet,支持其它QuerySet操作,包括filter(),order_by(),甚至是再次调用annotate()
>>> q =
Fruit.objects.annotate(store_num = Count('store')).filter(id__gt=3)
>>> q[0]
<Fruit: Fruit object>
>>> q[0].store_num
3
混用多个聚合函数
使用annotate()函数,混用多个聚合函数,会返回错误的结果,因为实现使用的是join查询,而非子查询。针对count聚合函数,可以使用distinct=True参数避免这个问题
例子:检索myapp_fruit表中第一个条记录,查询出售该类水果的商店数及该类水果的口味总数。
>>> fruit = Fruit.objects.first()
>>> fruit.store.count()
2
>>> fruit.taste_set.count()
3
>>> from django.db.models import Count
>>> q = Fruit.objects.annotate(Count('store'),
Count('taste'))
>>> q[0].store__count
6
>>> q[0].taste__count
6
解决方法:
>>> q = Fruit.objects.annotate(Count('store',
distinct=True), Count('taste', distinct=True))
>>> q[0].taste__count
3
>>> q[0].store__count
2
>>>
联合查询与聚合
有时候,需要获取和当前正在查询模块关联的另一个模块的相关聚合值,这个时候,可在聚合函数中,指定字段使用双下划线方式,关联相关模块进行join查询
例子:检索myapp_store表,查询每个商店正在出售水果种类中,最高价和最低价。
>>> q = Store.objects.annotate(min_price=Min('fruit__price'),
max_price=Max('fruit__price'))
>>> for item in q:
...
print(item.min_price, item.max_price)
...
10 20
19 20
None None
None None
None None
None None
联合查询的深度取决于你的查询要求。
例子:检索myapp_store表,查询每个商店正在出售水果种类中,产地最远是多远。
>>> from django.db.models import Min, Max
>>> q = Store.objects.annotate(max_distance=
Min('fruit__production_addr__distance'))
>>> for item in q:
...
print(item.name, item.max_distance)
...
aimi 40
ximi 20
xima None
masu None
gami None
gama None
反向关联查询
例:查询每个产地的水果种类数量(myapp_production_addr.id是myapp_fruit表的外键)
>>> q =
Production_addr.objects.annotate(cnt=Count('fruit'))
>>> for item in q:
...
print(item.addr, item.cnt)
...
changting 1
shanghang 1
longyan 1
例,检索所有产地产出的水果种类,最小价格
>>> q =
Production_addr.objects.aggregate(min_price=Min('fruit__price'))
>>> print(q)
{'min_price': 10}
对比(分组统计):
>>> q =
Production_addr.objects.annotate(min_price=Min('fruit__price'))
>>> for item in q:
...
print(item.addr, item.min_price)
...
changting 20
shanghang 16
longyan 10
不仅仅是针对外键,针对多对多关系也可以
>>> from django.db.models
import Avg
>>> q =
Taste.objects.annotate(avg_price=Avg('fruit__price'))
>>> for item in q:
...
print(item.taste, item.avg_price)
...
sour 20.0
sweet 20.0
bitter 20.0
聚合及其它QuerySet语句
filter()和exclude()
例子:统计myapp_fruit表中banana除外的水果种类的最小价
>>>
Fruit.objects.exclude(name='banana').aggregate(Min('price'))
{'price__min': 16}
filter也支持类似用法
Filtering on annotations
例子:检索myapp_store表,查询每个商店正在出售水果种类中最低价,过滤最低价小于等于10的。
>>>
Store.objects.annotate(min_price=Min('fruit__price')).filter(min_price__gt=10)
说明:先执行annotate,得到结果集,然后执行filter语句,得出结果。
注意:annotations和filter()、exclude()语句是有先后顺序之分的,后一步的处理依赖前一步的结果,顺序不一样,结果可能也会也不一样。
order_by()
例子:检索myapp_store表,查询每个商店正在出售水果种类中最低价,并按最低价升许排序。
>>>
Store.objects.annotate(min_price=Min('fruit__price')).order_by('min_price')
<QuerySet [<Store: Store object>, <Store:
Store object>, <Store: Store object>,<Store: Store object>,
<Store: Store object>, <Store: Store object>]>
values()
values()结合annotate的使用
例子:检索myapp_store表,按商店名称分组查询商店正在出售水果种类中最低价
>>>
Store.objects.values('name').annotate(min_price=Min('fruit__price'))
<QuerySet [{'min_price': 10, 'name': 'aimi'},
{'min_price': 19, 'name': 'ximi'}, {'min_price': None, 'name': 'xima'},
{'min_price': None, 'name': 'masu'}, {'min_price': None, 'name': 'gami'},
{'min_price': None, 'name': 'gama'}]>
>>>
可以理解为mysql中的分组统计,values('filed')中指定filed即为分组统计字段
注意:类似filter(),values和annotate也有先后顺序之分。
annotate和aggregate配合使用
例:
>>> Store.objects.values('name').annotate(min_price=Min('fruit__price')).aggregate(Avg('min_price'))
{'min_price__avg': 14.5}
说明,链式处理
其它例子
参考链接:https://www.cnblogs.com/YingLai/p/6601243.html
from django.db.models import Count, Avg, Max, Min, Sum
v
= models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
#
SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id
v=
models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
#
SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having
count(u_id) > 1
v
=
models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
#
SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having
count(u_id) > 1
更多详情,参考链接:
https://docs.djangoproject.com/en/1.11/topics/db/aggregation/#
Django model 层之聚合查询总结的更多相关文章
- django第10天(聚合查询,常用字段)
django第10天 聚合查询 聚合函数的使用场景 单独使用:不分组,只查聚合结果 分组使用:按字段分组,可查分组字段与聚合结果 导入聚合函数 from django.db.models import ...
- Django 学习 之ORM聚合查询分组查询与F查询与Q查询
一.聚合查询和分组查询 1.聚合查询aggregate 关于数据表的数据请见上一篇:Django 学习 之ORM多表操作(点我) aggregate(*args, **kwargs),只对一个组进行聚 ...
- Django模型层之字段查询参数及聚合函数
该系列教程系个人原创,并完整发布在个人官网刘江的博客和教程 所有转载本文者,需在顶部显著位置注明原作者及www.liujiangblog.com官网地址. 字段查询是指如何指定SQL WHERE子句的 ...
- Django框架:8、聚合查询、分组查询、F与Q查询、ORM查询优化、ORM事务操作、ORM常用字段类型、ORM常用字段参数
Django 数据库 目录 Django 数据库 一.聚合查询 二.分组查询 三.F查询与Q查询 1.F查询 2.Q查询 3.Q查询进阶操作 四.ORM查询优化 1.only与defer 五.ORM事 ...
- {django模型层(二)多表操作}一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询、分组查询、F查询和Q查询
Django基础五之django模型层(二)多表操作 本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 xxx 七 ...
- Django框架第七篇(模型层)--多表操作:一对多/多对多增删改,跨表查询(基于对象、基于双下划线跨表查询),聚合查询,分组查询,F查询与Q查询
一.多表操作 一对多字段的增删改(book表和publish表是一对多关系,publish_id字段) 增 create publish_id 传数字 (publish_id是数据库显示的字段名 ...
- django系列5.5--分组查询,聚合查询,F查询,Q查询,脚本中调用django环境
一.聚合查询 aggregate(*args, **args) 先引入需要的包,再使用聚合查询 #计算所有图书的平均价格 from django.db.models import Avg Book.o ...
- python 之 Django框架(orm单表查询、orm多表查询、聚合查询、分组查询、F查询、 Q查询、事务、Django ORM执行原生SQL)
12.329 orm单表查询 import os if __name__ == '__main__': # 指定当前py脚本需要加载的Django项目配置信息 os.environ.setdefaul ...
- django聚合查询
聚合¶ Django 数据库抽象API 描述了使用Django 查询来增删查改单个对象的方法.然而,有时候你需要获取的值需要根据一组对象聚合后才能得到.这份指南描述通过Django 查询来生成和返回聚 ...
- day056-58 django多表增加和查询基于对象和基于双下划线的多表查询聚合 分组查询 自定义标签过滤器 外部调用django环境 事务和锁
一.多表的创建 from django.db import models # Create your models here. class Author(models.Model): id = mod ...
随机推荐
- 基于 Kubernetes 的 CICD 基础设施即代码
在上一篇基于 Kubernetes 的基础设施即代码一文中,我概要地介绍了基于 Kubernetes 的 .NET Core 微服务和 CI/CD 动手实践工作坊使用的基础设施是如何使用代码描述的,以 ...
- 基于FPGA的计算器设计---第一版
欢迎各位朋友关注"郝旭帅电子设计团队",本篇为各位朋友介绍基于FPGA的计算器设计---第一版. 功能说明: 1. 计算器的显示屏幕为数码管. 2. 4x4矩阵键盘作为计算器的输入 ...
- NOIP模拟65
T1 网格图 解题思路 60pts 就是个zz做法..(我考场上造了一个 \(500\times 500\) 的 X,一看挺快,就以为 \(n^4\) 可以切,然而..) 正解有一点难度,对于每一个节 ...
- 基于Vue的二进制时钟组件 -- fx67llBinaryClock
fx67llClock Easy & Good Clock ! npm 组件说明 一个基于Vue的二进制时钟组件,没什么卵用,做着好玩,可以方便您装饰个人主页 使用步骤 npm install ...
- jquery的树状菜单
<body> <ul> <li>一级菜单 <ol> <li ...
- elasticsearch-head插件安装及启动,关闭命令
启动插件 /elasticsearch-head目录npm run start启动elasticsearch 不能使用root账号 切换账号:su es./bin/elasticsearch 打印日志 ...
- Elasticsearch之Nested Query nestedQuery查询数组
es是通过符合条件的json记录找出来,本身并不是将数据中的记录filter过滤.es nestedQuery不是过滤的结果,是匹配的这条es记录,所以数组中的其他的记录也会查询出来1.方法1:可以在 ...
- Feign的客户端注解@EnableFeignClients,解决No qualifying bean of type 'xx.xx.类' available注入报错
//如果使用Feign的客户端,请放开下列注释@EnableFeignClientsNo qualifying bean of type 'xx.xx.类' available //需要添加扫描的路径 ...
- 报错 ERR !npicode ELIFECYCLE dev: wue-cli-service serve
在系统变量 Path 里面加上:%SystemRoot%\system32,关掉终端,重新启动项目.
- python allure将生成报告和打开报告写到命令文件,并默认使用谷歌打开
背景: 使用python + pytest +allure,执行测试用例,并生成测试报告: allure报告要从收集的xml.json等文件,生成报告,不能直接点击报告的index.html,打开的报 ...