聚合

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

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. Tomcat项目内存参数调优

    一.常见的Java内存溢出有以下三种: 1. Java.lang.OutOfMemoryError: Java heap space 即JVM Heap溢出 解释说明:JVM在启动的时候会自动设置JV ...

  2. Thinkphp3.2下导入所需的类库 同java的Import 本函数有缓存功能

    * 导入所需的类库 同java的Import 本函数有缓存功能 * @param string $class 类库命名空间字符串 * @param string $baseUrl 起始路径 * @pa ...

  3. php curl模拟post请求的例子

    curl 在php中要模拟post请求数据提交我们会使用到curl函数,下面我来给大家举几个curl模拟post请求提交数据例子有需要的朋友可参考参考. 注意:curl函数在php中默认是不被支持的, ...

  4. 浅入不深出--vuex的简单使用

    什么是vuex,官网的描述是:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.状态管理模式包含3个部分: 1.state,驱动应用的数据源: 2.view,以声明方式将state映射到 ...

  5. iptables的使用

    四表五链 四表(table):raw.mangle.nat.filter 五链(chain):PREROUTING.INPUT.FORWARD.OUTPUT.POSTROUTING 每个表存在几个或全 ...

  6. 文件操作时:xreadlines和readlines的区别?

    二者使用时相同,但返回类型不同,xreadlines返回的是一个生成器,readlines返回的是list

  7. 二、python介绍

    python第一篇-------python介绍 一.python介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,Guido开始写Python语 ...

  8. [ARIA] Add aria-expanded to add semantic value and styling

    In this lesson, we will be going over the attribute aria-expanded. Instead of using a class like .op ...

  9. go语言的坑

    go语言在for循环中遍历的临时变量地址是一样的 func main() { //SetLogConfToEtcd() for i := 0; i < 5; i++ { a := i fmt.P ...

  10. vue transition实现页面切换效果

    我们都知道vue可以做成单页应用 点击的时候就能切换  如果我们要添加一些视觉效果 比如页面切换的时候有一个缓冲效果 这个时候就需要用到vue里的transition这个标签 在使用这个标签之前需要了 ...