本文从Django官方文档总结而来,将聚合的主要用法和查询集的常见方法做一归纳。

聚合

1. 聚合的产生来源于django数据库查询,通常我们使用django查询来完成增删查改,但是有时候需要更复杂的方法才能完成对数据的提取、筛选、更改,所以需要一组对象聚合来完成这种操作。模型举例如下:

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()

根据给出的模型,先引入三个例子:

# Total number of books.
>>> Book.objects.count()
2452 # Total number of books with publisher=BaloneyPress
>>> Book.objects.filter(publisher__name='BaloneyPress').count()
73
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}

注意几个点: .all() 和 .filter()    和  .count() 和 .aggregate() 为方法,前两者是返回新的查询集的方法(括号里面有参数),后两者是不返回查询集的方法 。 publisher 显然为字段名, name为字段查找,两者之间以双下划线连接 :__       price也是字段名,Avg 为聚合函数,用来求平均值。 以上提及的方法字段查找聚合函数将在查询集API中介绍。那么,我们先介绍聚合。

2.django提供了两种生成聚合的方法

1)从整个查询集生成统计值,主要用法:aggregate(*args, **kwargs)

aggregate()QuerySet 的一个终止子句,也就是说aggregate返回一个字典,包含根据QuerySet 计算得到的聚合值(平均数、和等等)。aggregate() 的每个参数指定返回的字典中将要包含的值。eg:

Book.objects.all()  # 返回所有图书的集合
>>> from django.db.models import Avg # 引入用来求平均值的聚合函数 Avg
>>> Book.objects.all().aggregate(Avg('price')) # 要计算所有书的平均价格,通过在查询集后面附加aggregate()子句实现
{'price__avg': 34.35} # 返回的是字典 >>> Book.objects.aggregate(Avg('price')) # all()在这里多余,可以省掉
{'price__avg': 34.35} # 返回的字典中,键为聚合值的标识符,由字段和聚合函数的名称自动生成 ,值为计算出来的聚合值 >>> Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35} # 为聚合值更换名称,提供参数average_price
>>> 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')}

2)为查询集的每一项成聚合,主要用法:annotate(*args, **kwargs)

这种方法为每一个对象都生成一个独立的汇总值,比如,如果你在检索一列图书,你可能想知道每一本书有多少作者参与。每本书和作者是多对多的关系。我们想要汇总QuerySet.中每本书里的这种关系。逐个对象的汇总结果可以由annotate()子句生成。当annotate()子句被指定之后,QuerySet中的每个对象都会被注上特定的值。这些注解的语法都和aggregate()子句所使用的相同。annotate()的每个参数都描述了将要被计算的聚合。

# Build an annotated queryset
>>> from django.db.models import Count
>>> q = Book.objects.annotate(Count('authors')) # 和aggregate语法相同,不同的是annotate返回的q是各个对象,可用q[0],q[1]等取出对象
# Interrogate the first object in the queryset
>>> q[0] # 返回的是第一个Book对象
<Book: The Definitive Guide to Django>
>>> q[0].authors__count # 编写第一本书的作者数目为2, authors为Book模型中的字段名,count为字段查询,所以用双下划线连接
2
# Interrogate the second object in the queryset
>>> q[1] # 返回的是第二个Book对象
<Book: Practical Django Projects>
>>> q[1].authors__count
1 >>> q = Book.objects.annotate(num_authors=Count('authors')) # 提供了自定义的num_authors别名代替了authors__count
>>> q[0].num_authors
2
>>> q[1].num_authors
1

与 aggregate() 不同的是, annotate() 不是一个终止子句。annotate()子句的返回结果是一个查询集 (QuerySet);这个 QuerySet可以用任何QuerySet方法进行修改,包括 filter()order_by()。发现aggregate 和 annotate用法的区别了吗,再次举例如下(在聚合函数中指定聚合字段时,Django 允许你使用同样的 双下划线 表示关联关系,):

>>> from django.db.models import Max, Min
>>> Store.objects.annotate(min_price=Min('books__price'), max_price=Max('books__price'))
# 查找每个商店提供的图书的价格范围
>>> Store.objects.aggregate(min_price=Min('books__price'), max_price=Max('books__price'))
# 查找所有书店中最便宜的书和最贵的书的价格
>>> Store.objects.aggregate(youngest_age=Min('books__authors__age'))
# 利用双下划线延伸关系链,查找所有书店中的所有作者的最小年龄

3. 聚合和其他查询子句

filter() 和 exclude()

>>> from django.db.models import Count, Avg
>>> Book.objects.filter(name__startswith="Django").annotate(num_authors=Count('authors'))
# 使用annotate() 子句时,过滤器有限制注解对象的作用。例如,得到每本以 "Django" 为书名开头的图书作者的总数
>>> Book.objects.filter(name__startswith="Django").aggregate(Avg('price'))
# 使用aggregate()子句时,过滤器有限制聚合对象的作用。例如,算出所有以 "Django" 为书名开头的图书平均价格
>>> Book.objects.annotate(num_authors=Count('authors')).filter(num_authors__gt=1)
# 得到不止一个作者的图书

注意以上annotate() 和 filter()子句的顺序,顺序不同查询结果也会不同(后者筛选的出版商为前者的子集。):

>>> Publisher.objects.annotate(num_books=Count('book')).filter(book__rating__gt=3.0)
# 返回了至少出版了一本好书(评分大于 3 分)的出版商, 在这些出版商中包含出版商所发行的所有图书!(这些出版商中每个出版商只要发行过一本>3的书就算)
>>> 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()

>>> Author.objects.annotate(average_rating=Avg('book__rating'))
# 返回所有作者及他所著图书的平均评分
>>> Author.objects.values('name').annotate(average_rating=Avg('book__rating'))
# 作者先按名称分组,意味着若两位作者同名则查询结果被合并!,两者均分被算为一个
>>> Author.objects.annotate(average_rating=Avg('book__rating')).values('name', 'average_rating')

# 这段代码交换了value和average顺序,将给每个作者添加一个唯一的字段,但只有作者名称和average_rating 注解会返回在输出结果中

4.查询集(QuerySet)API 查询

本质上,可以创建、过滤、切片和传递查询集而不用真实操作数据库。在你对查询集做求值之前,不会发生任何实际的数据库操作。可以通过迭代、切片、序列化/缓存、repr()、len()、list()、bool()

1)返回新的查询集方法

filter(): 返回一个新的QuerySet,包含与给定的查询参数匹配的对象。

exclude():返回一个新的QuerySet,它包含不满足给定的查找参数的对象。

annotate(*args, **kwargs): 使用提供的查询表达式Annotate查询集中的每个对象。
order_by(*fields):  默认情况下,QuerySet 根据模型Meta 类的ordering 选项排序。你可以使用order_by 方法给每个QuerySet 指定特定的排序。
...

QuerySet API参考

tricks: 利用聚合解决博客中增加点击排行和站长推荐侧边栏的方法:

views.py:

 # 点击排行
click_list = Article.objects.all().order_by('-click_count') # 站长推荐
command_list = Article.objects.filter(is_recommend__isnull=False)

base.html:

    <div  class="bd bd-news">
<ul>
{% for article in article_comment_list %}
<li><a href="/" target="_blank">{{ article.title }}</a></li>
{% endfor %}
</ul>
</div>
<div class="bd bd-news">
<ul>
{% for article in command_list %}
<li><a href="/" target="_blank">{{ article.title }}</a></li>
{% endfor %}
</ul>
</div>

final:

Django 聚合与查询集API实现侧边栏的更多相关文章

  1. 查询集API -- Django从入门到精通系列教程

    该系列教程系个人原创,并完整发布在个人官网刘江的博客和教程 所有转载本文者,需在顶部显著位置注明原作者及www.liujiangblog.com官网地址. Python及Django学习QQ群:453 ...

  2. django查询集API

    本节将详细介绍查询集的API,它建立在下面的模型基础上,与上一节的模型相同: from django.db import models class Blog(models.Model): name = ...

  3. django 查询集 API

    filter 表示=, 返回一个新的QuerySet,包含与给定的查询参数匹配的对象.exclude 表示!=. 返回一个新的QuerySet,它包含不满足给定的查找参数的对象. annotate 使 ...

  4. 第一章:模型层 - 9:查询集API

    本节将详细介绍查询集的API,它建立在下面的模型基础上,与上一节的模型相同: from django.db import models class Blog(models.Model): name = ...

  5. Django聚合分组查询、常用字段

    首先回顾sql中聚合和分组的概念: 如果没有分组,会把整张表作为一个大组,查询字段必须是聚合结果:如果有分组,分组之后,必须要使用聚合的结果作为having的条件. 聚合查询 聚合:aggregate ...

  6. django 聚合统计查询

    from django.shortcuts import renderfrom django.http import HttpResponsefrom django.db.models import ...

  7. Django 查询集简述

    通过模型中的管理器构造一个查询集(QuerySet),来从数据库中获取对象.查询集表示从数据库中取出来的对象的集合.它可以含有零个.一个或者多个过滤器.过滤器基于所给的参数限制查询的结果. 从SQL ...

  8. Django 多表查询

    多表查询是模型层的重要功能之一, Django提供了一套基于关联字段独特的解决方案. ForeignKey 来自Django官方文档的模型示例: from django.db import model ...

  9. 查询集 QuerySet和管理器Manager

    查询集 QuerySet 查询集,也称查询结果集.QuerySet,表示从数据库中获取的对象集合. 当调用如下过滤器方法时,Django会返回查询集(而不是简单的列表): all():返回所有数据. ...

随机推荐

  1. Leetcode 189.旋转数组 By Python

    给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: [1,2,3,4,5,6,7] 和 k = 3 输出: [5,6,7,1,2,3,4] 解释: 向右旋转 1 ...

  2. 【Linux】fg、bg让你的进程在前后台之间切换

    Linux下的fg和bg命令是进程的前后台调度命令,即将指定号码(非进程号)的命令进程放到前台或后台运行.比如一个需要长时间运行的命令,我们就希望把它放入后台,这样就不会阻塞当前的操作:而一些服务型的 ...

  3. 【loj3056】【hnoi2019】多边形

    题目 描述 ​ 给出一个 \(n\) 个点的多边形初始的三角剖分: ​ 一次合法的旋转定义为 \((a,b,c,d)\) ,满足 \(a<b<c<d\) : ​ 并且存在边\((a, ...

  4. 猜数字小游戏,很naive......

    这里用到了随机数生成器以及ctime #include <cstdio> #include <cstdlib> #include <ctime> #include ...

  5. 洛谷P3295 萌萌哒 并查集 + ST表

    又切一道紫题!!! 成功的(看了一吨题解之后),我A掉了第二道紫题. 好,我们仔细观察,发现这是一个排列组合问题. 有些限定条件,要相等的地方,我们就用并查集并起来.最后一查有多少个并查集,就有多少个 ...

  6. Python基本数据类型——元组和集合

    元组 tuple tuple和list非常类似,但是tuple一旦初始化就不能修改.元组采用圆括号表示. 例如: >>> tuple = (1,2,3) >>> t ...

  7. Spring + Shiro 项目 + HttpSessionListener 【调用springService问题】&【Session失效问题】

    功能描述: 当用户退出(主动)或者关闭浏览器(session超时)的时候,利用本次登录Ip更新上次登录IP.有人可能要问,你在用户登录的时候记录不就行了.可是我有两个字段,一个为本次登录IP,另外一个 ...

  8. P1282 多米诺骨牌

    P1282 多米诺骨牌 题目描述 多米诺骨牌有上下2个方块组成,每个方块中有1~6个点.现有排成行的 上方块中点数之和记为S1,下方块中点数之和记为S2,它们的差为|S1-S2|.例如在图8-1中,S ...

  9. SpringBoot使用redis缓存List<Object>

    一.概述 最近在做性能优化,之前有一个业务是这样实现的: 1.温度报警后第三方通讯管理机直接把报警信息保存到数据库 2.我们在数据库中添加触发器,(BEFORE INSERT)根据这条报警信息处理业务 ...

  10. SQL记录-PLSQL基本语法与数据类型

    PL/SQL基本语法 PL/SQL是一种块结构的语言,这意味着PL/SQL程序被划分和编写代码的逻辑块.每块由三个子部分组成: S.N. 段和说明 1 声明 此部分开头使用关键字DECLARE.它是一 ...