聚合

我们将引用以下模型。这些模型用来记录多个网上书店的库存。

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, on_delete=models.CASCADE)
pubdate = models.DateField() class Store(models.Model):
name = models.CharField(max_length=300)
books = models.ManyToManyField(Book)
registered_users = models.PositiveIntegerField()

速查表

下面是根据以上模型执行常见的聚合查询:

# Total number of books.
>>> Book.objects.count()
2452 # Total number of books with publisher=BaloneyPress
>>> Book.objects.filter(publisher__name='BaloneyPress').count()
73 # Average price across all books.
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35} # Max price across all books.
>>> from django.db.models import Max
>>> Book.objects.all().aggregate(Max('price'))
{'price__max': Decimal('81.20')} # Difference between the highest priced book and the average price of all books.
>>> from django.db.models import FloatField
>>> Book.objects.aggregate(
... price_diff=Max('price', output_field=FloatField()) - Avg('price'))
{'price_diff': 46.85} # All the following queries involve traversing the Book<->Publisher
# foreign key relationship backwards. # Each publisher, each with a count of books as a "num_books" attribute.
>>> from django.db.models import Count
>>> pubs = Publisher.objects.annotate(num_books=Count('book'))
>>> pubs
<QuerySet [<Publisher: BaloneyPress>, <Publisher: SalamiPress>, ...]>
>>> pubs[0].num_books
73 # Each publisher, with a separate count of books with a rating above and below 5
>>> from django.db.models import Q
>>> above_5 = Count('book', filter=Q(book__rating__gt=5))
>>> below_5 = Count('book', filter=Q(book__rating__lte=5))
>>> pubs = Publisher.objects.annotate(below_5=below_5).annotate(above_5=above_5)
>>> pubs[0].above_5
23
>>> pubs[0].below_5
12 # The top 5 publishers, in order by number of books.
>>> pubs = Publisher.objects.annotate(num_books=Count('book')).order_by('-num_books')[:5]
>>> pubs[0].num_books
1323

QuerySet上生成聚合

Django提供了两种生成聚合的方法。第一种方法是从整个QuerySet生成汇总值。比如你想要计算所有在售书的平均价格.Django的查询语法提供了一种用来描述所有图书集合的方法:

>>> Book.objects.all()

通过可以在QuerySet后添加aggregate()[主语]来计算QuerySet对象的汇总值。

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

all()是在本例中多余的,所以这可以简化为:

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

aggregate()子句的参数描述了我们想要计算的聚合值 - 在本例中,priceBook模型上字段 的平均值。


aggregate()是一个终结子句QuerySet,当被调用时,返回一个名称 - 值对的字典。名称是聚合值的标识符; 该值是计算的聚合。该名称是从字段名称和聚合函数自动生成的。如果要手动指定聚合值的名称,可以通过在指定聚合子句时提供该名称来实现:


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

如果要生成多个聚合,只需在该aggregate()子句中添加另一个参数即可。因此,如果我们还想了解所有图书的最高和最低价格,我们会发出查询:


>>> 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')}

可以使用该annotate()子句生成每对象摘要。当一个annotate()指定的子句,在每个对象QuerySet 将具有指定值进行注释。

这些注释的语法与用于该aggregate()子句的语法相同 。每个参数annotate()描述要计算的聚合。例如,要注释具有作者数量的书籍:

# Build an annotated queryset
>>> from django.db.models import Count
>>> q = Book.objects.annotate(Count('authors'))
# Interrogate the first object in the queryset
>>> q[0]
<Book: The Definitive Guide to Django>
>>> q[0].authors__count
2
# Interrogate the second object in the queryset
>>> q[1]
<Book: Practical Django Projects>
>>> q[1].authors__count
1

当指定要在聚合函数中聚合的字段时,Django将允许您使用在引用过滤器中的相关字段时使用的相同双下划线表示法。然后Django将处理检索和聚合相关值所需的任何表连接。

例如,要查找每个商店中提供的书籍的价格范围,您可以使用注释:

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

这告诉Django检索Store模型,与模型连接(通过多对多关系)Book,并在书模型的价格字段上聚合以产生最小值和最大值。

同样的规则适用于该aggregate()条款。如果您想知道任何商店中可供出售的任何书籍的最低价格和最高价格,您可以使用聚合:

>>> Store.objects.aggregate(min_price=Min('books__price'), max_price=Max('books__price'))

我们可以要求所有发布者注释其各自的总账簿计数器(注意我们如何使用'book'指定 Publisher- > Book反向外键跳):


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

(每次Publisher在由此而来QuerySet将有一个名为额外属性book__count。)


我们还可以要求每个出版商管理的最老的书籍:


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

(生成的字典会有一个名为'oldest_pubdate'。如果没有指定这样的别名,那就相当长了'book__pubdate__min'。)


filter()exclude()


聚合也可以参与过滤器。应用于普通模型字段的任何filter()(或 exclude())将具有约束考虑进行聚合的对象的效果。


annotate()子句一起使用时,过滤器具有约束计算注释的对象的效果。例如,您可以使用查询生成带有标题以“Django”开头的所有书籍的带注释的列表:


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

aggregate()子句一起使用时,过滤器具有约束计算聚合的对象的效果。例如,您可以使用查询生成标题以“Django”开头的所有书籍的平均价格:


>>> Book.objects.filter(name__startswith="Django").aggregate(Avg('price'))

过滤注释

也可以过滤带注释的值。注释的别名可以使用filter()exclude()子句以与任何其他模型字段相同的方式使用。

例如,要生成包含多个作者的书籍列表,您可以发出查询:

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

此查询生成带注释的结果集,然后基于该批注生成过滤器。

如果需要两个带有两个单独过滤器的注释,则可以将 filter参数与任何聚合一起使用。例如,要生成具有高评价书籍数量的作者列表:

>>> highly_rated = Count('books', filter=Q(books__rating__gte=7))
>>> Author.objects.annotate(num_books=Count('books'), highly_rated_books=highly_rated)

Author结果集中的每个都将具有num_books和 highly_rated_books属性。


order_by()


注释可以用作排序的基础。定义order_by()子句时,您提供的聚合可以引用annotate()在查询中定义为子句一部分的任何别名。


例如,要按照QuerySet为图书贡献的作者数量订购图书,您可以使用以下查询:


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

values()


通常,注解值会添加到每个对象上,即被一个注解的QuerySet将会为初始QuerySet的每个对象报道查看一个查询查询结果集。然而,使用当values()¸...。来对查询查询结果集进行约束时,生成注解值的方法会稍有不同。在不是原始QuerySet中对每个对象添加注解并报道查看,根据而是定义在values()[主语]中的字段组合先对查询查询结果进行分组,再对每个单独的分组进行注解,这个注解值是根据分组中所有的对象计算得到的。


下面是一个关于作者的查询例子,查询每个作者所着书的平均评分:


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

这段代码返回的是数据库中的所有作者及其所着书的平均评分。


如果但是你使用values()[主语],结果会稍有不同:


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

在这个例子中,作者会按名字分组,所以你只能得到不重名的作者分组的注解值。这意味着如果你有两个作者同名,那么他们原本各自的查询结果将被合并到同一个结果中;两个作者的所有评分都将被计算为一个平均分。


annotate()状语从句:values()的顺序


使用状语从句:filter()一样,于作用英文查询某个的annotate()状语从句:values()[主语]的顺序非常重要。如果values()[主语]在annotate()之前,根据就会values()[主语]产生的分组来计算注解。


如果然而annotate()[主语]在values()之前,就会根据整个查询集生成注解。这种情况下,values()子句只能限制输出的字段。


举个例子,我们如果颠倒上个例子中values()状语从句:annotate()的顺序:


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

这段代码将为每个作者添加一个唯一注解,只有但作者姓名状语从句:average_rating注解会报道查看在输出查询查询结果中。


您还应注意,average_rating已明确包含在要返回的值列表中。由于values()annotate()子句的排序,这是必需的。


如果该values()子句在该子句之前annotate(),则任何注释都将自动添加到结果集中。但是,如果在values() 子句之后应用该annotate()子句,则需要显式包含聚合列。

 

 

Django文档阅读之聚合的更多相关文章

  1. Django文档阅读-Day1

    Django文档阅读-Day1 Django at a glance Design your model from djano.db import models #数据库操作API位置 class R ...

  2. Django文档阅读-Day2

    Django文档阅读 - Day2 Writing your first Django app, part 1 You can tell Django is installed and which v ...

  3. Django文档阅读-Day3

    Django文档阅读-Day3 Writing your first Django app, part 3 Overview A view is a "type" of Web p ...

  4. 吴裕雄--天生自然PythonDjangoWeb企业开发:Django文档阅读简介

    Django是基于MVC模式的框架,虽然也被称为“MTV”的模式,但是大同小异.对我们来说,需要了解的是无论是MVC模式还是MTV模式,甚至是其他的什么模式,都是为了解耦.把一个软件系统划分为一层一层 ...

  5. Django文档阅读之模型

    模型 模型是您的数据唯一而且准确的信息来源.它包含您正在储存的数据的重要字段和行为.一般来说,每一个模型都映射一个数据库表. 基础: 每个模型都是一个 Python 的类,这些类继承 django.d ...

  6. Django文档阅读之执行原始SQL查询

    Django提供了两种执行原始SQL查询的方法:可以使用Manager.raw()来执行原始查询并返回模型实例,或者可以完全避免模型层直接执行自定义SQL. 每次编写原始SQL时都要关注防止SQL注入 ...

  7. Django文档阅读之查询

    创建对象 为了在Python对象中表示数据库表数据,Django使用直观的系统:模型类表示数据库表,该类的实例表示数据库表中的特定记录. 要创建对象,请使用模型类的关键字参数对其进行实例化,然后调用s ...

  8. Node.js的下载、安装、配置、Hello World、文档阅读

    Node.js的下载.安装.配置.Hello World.文档阅读

  9. 我的Cocos Creator成长之路1环境搭建以及基本的文档阅读

    本人原来一直是做cocos-js和cocos-lua的,应公司发展需要,现转型为creator.会在自己的博客上记录自己的成长之路. 1.文档阅读:(cocos的官方文档) http://docs.c ...

随机推荐

  1. postgres —— 有序集与假象聚集

    有序集 -- 有序集.分组后,按给定顺序排序,再进行计算 SELECT region, percentile_disc(0.5) WITHIN GROUP (order by production) ...

  2. postgres常用运维sql

    1.查看数据库大小 select pg_database_size('log_analysis'); postgres=# select pg_database_size('postExpress') ...

  3. 【深入ASP.NET原理系列】--Asp.Net Mvc和Asp.Net WebForm实际上共用一套ASP.NET请求管道

    .NET FrameWork4在系统全局配置文件(如在如下目录中C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config) 中添加了一个名字叫Url ...

  4. EntityFramework6 学习笔记(二)

    使用EF对数据库进行操作,整个过程就像操作数组一样,我们只管修改或向集合中添加值,最后通知EF保存修改后的结果就可以了. 准备工作 为了演示,我在数据库中建了两张表.class表用于表示班级,clas ...

  5. 做勇敢女孩 https://www.bilibili.com/video/av14346123?from=search&seid=14078047355739050009

    So a few years ago, I did something really brave, or some would say really stupid. I ran for congres ...

  6. 如何把上传图片时候的文件对象转换为图片的url !

    getObjectURL(file) { var url = null; if (window.createObjectURL != undefined) { url = window.createO ...

  7. urql 高度可自定义&&多功能的react graphql client

    urql 是一个很不错的graphql client,使用简单,功能强大,通过exchanges 实现了完整的自定义特性 通过urql 的exchanges 我们可以实现灵活的cache策略 参考资料 ...

  8. P4218 [CTSC2010]珠宝商

    P4218 [CTSC2010]珠宝商 神题... 可以想到点分治,细节不写了... (学了个新姿势,sam可以在前面加字符 但是一次点分治只能做到\(O(m)\),考虑\(\sqrt n\)点分治, ...

  9. 洛谷P1270 访问美术馆

    题目 树形DP,首先考虑递归建图,类似于线段树的中序遍历.然后取状态dp[i][j]表示i点花费j时间所偷到的最多的画,有方程: \(dp[now][nwt] = max(dp[now][nwt], ...

  10. element ui 合计/table show-summary

    在el-table 上面加上show-summary就可以对table的数据进行合计 但是上次出现了合计栏有的为空,有的合计不对的情况,如果出现的是空,那么说明你渲染的数据有undefine(即后台返 ...