在当今根据需求而不断调整而成的应用程序中,通常不仅需要能依常规的字段,如字母顺序或创建日期,来对项目进行排序,还需要按其他某种动态数据对项目进行排序。Djngo聚合就能满足这些要求。

以下面的Model为例

from django.db import models

class Author(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField() class Publisher(models.Model):
name = models.CharField(max_length=300)
num_awards = models.IntegerField() class Book(models.Model):
name = models.CharField(max_length=300)
pages = models.IntegerField()
price = models.DecimalField(max_digits=10, decimal_places=2)
rating = models.FloatField()
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
pubdate = models.DateField() class Store(models.Model):
name = models.CharField(max_length=300)
books = models.ManyToManyField(Book)
registered_users = models.PositiveIntegerField()

快速了解

# books总数量.
>>> Book.objects.count()
2452 # Total number of books with publisher=BaloneyPress
>>> Book.objects.filter(publisher__name='BaloneyPress').count()
73 # books的平均price.
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35} # books的最大price.
>>> from django.db.models import Max
>>> Book.objects.all().aggregate(Max('price'))
{'price__max': Decimal('81.20')} # All the following queries involve traversing the Book<->Publisher
# many-to-many relationship backward # 为每个publisher添加个num_books属性,即每个pulisher出版的book的数量.
>>> from django.db.models import Count
>>> pubs = Publisher.objects.annotate(num_books=Count('book'))
>>> pubs
[<Publisher BaloneyPress>, <Publisher SalamiPress>, ...]
>>> pubs[0].num_books
73 # 根据num_book属性排序.
>>> pubs = Publisher.objects.annotate(num_books=Count('book')).order_by('-num_books')[:5]
>>> pubs[0].num_books
1323

聚合生成Generating aggregates over a QuerySet

Django有两种方法来生成聚合。第一种方法是为整个QuerySet生成聚合值,例如为全部的books生成price的平均值:

>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}

可以简略为:

>>> Book.objects.aggregate(Avg('price'))
{'price__avg': 34.35}

函数aggregate()的参数是一系列聚合函数aggregate functions:

Avg

# 返回平均值

Count

# class Count(field, distinct=False)

# 返回计数。当参数distinct=True时,返回unique的对象数目。

Max

# 返回最大值

Min

# 返回最小值.

StdDev

# class StdDev(field, sample=False)返回标准偏差
# 有一个参数sample # 默认情况下sample=False,返回总体标准偏差,如果sample=True,返回样本标准偏差。

Sum

# 返回总值

Variance

# class Variance(field, sample=False)
# 返回方差 # 有一个参数sample,默认返回总体方差,sample设为True时返回样本方差。

aggregate()方法被调用时,返回一个键值对字典,可以指定key的名字:

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

如果你想生成多个聚合,你只需要添加另一个参数。所以,如果我们还想知道所有书的最高和最低的价格:

>>> from django.db.models import Avg, Max, Min
>>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
{'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}

为查询集的每个对象生成聚合值Generating aggregates for each item in a QuerySet

这是生成聚合值的第二种方法。比如你要检索每本书有多少个作者。book和author是manytomany的关系,我们可以为每本书总结出这种关系。

每个对象的总结可以用方法annotate()生成:

# 建立一个annotate QuerySet
>>> from django.db.models import Count
>>> q = Book.objects.annotate(Count('authors'))
# 第一个对象
>>> q[0]
<Book: The Definitive Guide to Django>
>>> q[0].authors__count
2
# 第二个对象
>>> q[1]
<Book: Practical Django Projects>
>>> q[1].authors__count
1

也可以指定生成属性的名字:

>>> q = Book.objects.annotate(num_authors=Count('authors'))
>>> q[0].num_authors
2
>>> q[1].num_authors
1

和aggregate()不同,annotate()的输出是一个QuerySet。

联合聚合Joins and aggregates

目前为止,我们聚合查询的field都属于我们要查询的Model,我们也可以用其它Model的field来进行聚合查询,例如:

>>> from django.db.models import Max, Min
>>> Store.objects.annotate(min_price=Min('books__price'), max_price=Max('books__price'))

这样就可以查询每个Store里面books的价格范围

联合链的深度可以随心所欲:

>>> Store.objects.aggregate(youngest_age=Min('books__authors__age'))

反向关系Following relationships backwards

通过book反向查询publisher:

>>> from django.db.models import Count, Min, Sum, Avg
>>> Publisher.objects.annotate(Count('book'))

返回的QuerySet的每个publisher都会带一个属性book_count。

查询出版最久的书的出版日期:

>>> Publisher.objects.aggregate(oldest_pubdate=Min('book__pubdate'))

查询每个作者写的书的总页数:

>>> Author.objects.annotate(total_pages=Sum('book__pages'))

查询所有作者写的书的平均rating:

>>> Author.objects.aggregate(average_rating=Avg('book__rating'))

聚合和其它查询集操作Aggregations and other QuerySet clauses

filter() and exclude()

聚合可以和filter和exclude一起使用:

>>> from django.db.models import Count, Avg
>>> Book.objects.filter(name__startswith="Django").annotate(num_authors=Count('authors'))
>>> Book.objects.filter(name__startswith="Django").aggregate(Avg('price'))

可以根据聚合值进行筛选:

>>> Book.objects.annotate(num_authors=Count('authors')).filter(num_authors__gt=1)

编写一个包含annotate()和filter()从句的复杂查询时,要特别注意作用于QuerySet的从句的顺序顺序的不同,产生的意义也不同:

>>> Publisher.objects.annotate(num_books=Count('book')).filter(book__rating__gt=3.0)
>>> Publisher.objects.filter(book__rating__gt=3.0).annotate(num_books=Count('book'))

两个查询都返回了至少出版了一本好书(评分大于3分)的出版商的列表。但是第一个查询的注解包含其该出版商发行的所有图书的总数;而第二个查询的注解只包含出版过好书的出版商的所发行的好书(评分大于3分)总数。在第一个查询中,注解在过滤器之前,所以过滤器对注解没有影响。在第二个查询中,过滤器在注解之前,所以,在计算注解值时,过滤器就限制了参与运算的对象的范围

order_by()

可以根据聚合值进行排序

>>> Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')

values()

通常,注解annotate是添加到每一个对象上的,一个执行了注解操作的查询集 QuerySet 所返回的结果中,每个对象都添加了一个注解值。但是,如果使用了values()从句,它就会限制结果中列的范围,对注解赋值的方法就会完全不同。就不是在原始的 QuerySet 返回结果中对每个对象中添加注解,而是根据定义在 values() 从句中的字段组合对先结果进行唯一的分组,再根据每个分组算出注解值,这个注解值是根据分组中所有的成员计算而得的:

>>> Author.objects.values('name').annotate(average_rating=Avg('book__rating'))

这样的写法下,QuerySet会根据name进行组合,返回的是每个unique name的聚合值。如果有两个作者有相同的名字,这两个作者会被当做一个计算,他们的books会合在一起。

>>> Author.objects.annotate(average_rating=Avg('book__rating')).values('name', 'average_rating')

位置互换后,会为每个author都生成一个average_rating,而且只会输出每个author的name和average_rating。

默认排序下使用聚合:

from django.db import models

class Item(models.Model):
name = models.CharField(max_length=10)
data = models.IntegerField() class Meta:
ordering = ["name"]

如果你想知道每个非重复的data值出现的次数,你可能这样写:

# Warning: 不正确的写法
Item.objects.values("data").annotate(Count("id"))

这部分代码想通过使用它们公共的data值来分组Item对象,然后在每个分组中得到id值的总数。但是上面那样做是行不通的。这是因为默认排序项中的name也是一个分组项,所以这个查询会根据非重复的(data,name)进行分组,而这并不是你本来想要的结果。所以,你需要这样写来去除默认排序的影响:

Item.objects.values("data").annotate(Count("id")).order_by()

Aggregating annotations

>>> from django.db.models import Count, Avg
>>> Book.objects.annotate(num_authors=Count('authors')).aggregate(Avg('num_authors'))
{'num_authors__avg': 1.66}

Django学习笔记之Django ORM Aggregation聚合详解的更多相关文章

  1. Linux防火墙iptables学习笔记(三)iptables命令详解和举例[转载]

     Linux防火墙iptables学习笔记(三)iptables命令详解和举例 2008-10-16 23:45:46 转载 网上看到这个配置讲解得还比较易懂,就转过来了,大家一起看下,希望对您工作能 ...

  2. (转)live555学习笔记10-h264 RTP传输详解(2)

    参考: 1,live555学习笔记10-h264 RTP传输详解(2) http://blog.csdn.net/niu_gao/article/details/6936108 2,H264 sps ...

  3. Django学习笔记之Django Form表单详解

    知识预览 构建一个表单 在Django 中构建一个表单 Django Form 类详解 使用表单模板 回到顶部 构建一个表单 假设你想在你的网站上创建一个简单的表单,以获得用户的名字.你需要类似这样的 ...

  4. Django学习笔记之Django中间件

    准备 我们在前面的课程中已经学会了给视图函数加装饰器来判断是用户是否登录,把没有登录的用户请求跳转到登录页面.我们通过给几个特定视图函数加装饰器实现了这个需求.但是以后添加的视图函数可能也需要加上装饰 ...

  5. Django学习笔记之Django Form表单

    Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否 ...

  6. 学习笔记--Grunt、安装、图文详解

    学习笔记--Git安装.图文详解 安装Git成功后,现在安装Gruntjs,官网:http://gruntjs.com/ 一.安装node 参考node.js 安装.图文详解 (最新的node会自动安 ...

  7. 大数据学习笔记——Spark工作机制以及API详解

    Spark工作机制以及API详解 本篇文章将会承接上篇关于如何部署Spark分布式集群的博客,会先对RDD编程中常见的API进行一个整理,接着再结合源代码以及注释详细地解读spark的作业提交流程,调 ...

  8. Java8学习笔记(五)--Stream API详解[转]

    为什么需要 Stream Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 ...

  9. SNMP学习笔记之SNMP 原理与实战详解

    原文地址:http://freeloda.blog.51cto.com/2033581/1306743 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法 ...

随机推荐

  1. Android APK反编译详解

    这段时间在学Android应用开发,在想既然是用Java开发的应该很好反编译从而得到源代码吧,google了一下,确实很简单,以下是我的实践过程. 在此郑重声明,贴出来的目的不是为了去破解人家的软件, ...

  2. SSH电力项目九--运行监控首页显示

    需求:在首页显示出设备运行情况,并去掉<br>换行符,每隔十分钟刷新一次页面. ElecMenuAction.java 首先注入运行监控service public class ElecM ...

  3. powerdesigner 导入SQL脚本生成模型

  4. 170502、linux下配置jdk8

    1.下载源码包jdk-8u45-linux-x64.tar.gz(省略) 2.解压 tar -zxvf jdk-8u45-linux-x64.tar.gz 3.配置jdk vi /etc/profil ...

  5. java基础之Flex弹性布局、JSP错误处理以及Log4J

    一.Flex弹性布局 1.产生的比较晚,目前在移动网页开发中可以使用,而且逐渐成为主流. 在桌面网页开发中使用的比较少(主要是桌面浏览器的兼容性问题更加严重) 2.开启方法: 在容器标签上加上 dis ...

  6. Exchange Database Status(Copy Status ,Content Index State,QueueLength,Move Status...)

    Copy Status Description Mounted The active copy is online and accepting client connections. Only the ...

  7. 2017 Multi-University Training Contest - Team 8

    HDU6140 Hybrid Crystals 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6140 题目意思:这场多校是真的坑,题目爆长,心态爆炸, ...

  8. tomcat启动报错:Injection of autowired dependencies failed

    Error creating bean with name 'backPrintPaperController': Injection of autowired dependencies failed ...

  9. HBase简单API

    一.使用IDEA的maven工程,工程结构如下: 二.maven的依赖pom.xml文件 <?xml version="1.0" encoding="UTF-8&q ...

  10. linux 这是定时任务

    1. 编写shell脚本:vim test.sh #/bin/bash echo "hello world" 2.crontab任务配置基本格式: *   * * * * comm ...