Django中分组查询(annotate 和 aggregate 使用)

在 Django 中,aggregate() 和 annotate() 是两个常用的聚合函数。它们都可以用来对一组查询结果进行聚合操作,但它们的作用是有所不同的。

aggregate() 是用于聚合整个查询集的结果,通常用于返回一个值,例如计算查询集中所有结果的数量、平均值、最大值或最小值等。使用 aggregate() 函数时,需要用到 SQL 中的聚合函数(如 Count、Sum、Min、Max、Avg 等) 返回的是字典

from django.db.models import Count
from myapp.models import MyModel# 统计所有模型对象的数量
obj_count = MyModel.objects.aggregate(obj_count=Count('id'))# 输出结果
print(obj_count)

 annotate() 的作用是对数据库中每一行进行聚合操作,并返回一个新的查询集,通常用于计算每个分组的聚合值。使用 annotate() 函数时,需要用到 SQL 中的 GROUP BY 语句。返回的是queryset 。filter在annotate()函数前是筛选后分组,在annotate()函数后是分组后过滤类似与group by 后的having

from django.db.models import Count
from myapp.models import MyModel# 统计每个分类下的记录数量
category_count = MyModel.objects.values('category').annotate(cat_count=Count('id'))# 输出结果
print(category_count)

使用 values() 函数指定要分组的字段 category,然后使用 Count 函数对 id 字段进行聚合操作,并为结果起一个别名 cat_count

如何使用aggregate函数

Django还提供了另外两种统计查询方法,首先来看看aggregate

SELECTCOUNT(id) AS id__count
FROMauth_user;
from django.db.models import CountUser.objects.aggregate(Count('id'))

为了使用aggregate,我们导入了Count函数,aggregate以另外一个实现统计查询的表达式为参数,在本例中,我们使用主键id来查询数据库表中的行的数量。

aggregate的结果是一个字典对象:

>>> from django.db.models import Count
>>> User.objects.aggregate(Count('id'))
{"id__count": 891}

键的名称是从字段的名称和查询函数的名称派生的,在本例中,键名是id__count。我们最好不要使用这样的命名方式,而是要自己设定名称:

SELECTCOUNT(id) as total
FROMauth_user;
>>> from django.db.models import Count
>>> User.objects.aggregate(total=Count('id'))
{"total": 891}

aggregate参数的名称,就是返回值字典的键。

如何实现Group By

使用aggregate,我们得到数据表进行聚合查询结果,这很有用,但我们还希望对指定的行应用此操作。

让我们根据用户的活动状态来统计用户数:

SELECTis_active,COUNT(id) AS total
FROMauth_user
GROUP BYis_active
(User.objects
.values('is_active')
.annotate(total=Count('id')))

这次使用了annotate函数。我们使用valuesannotate的组合来完成分组查询:

  • values('is_active'):分组依据
  • annotate(total=Count('id')):要查询的内容

顺序很重要:如果在annotate之前调用values失败,不会产生查询结果。

aggregate一样,annotate的参数名称是QuerySet返回值的键,示例中就是total

分组筛选

若要对筛选查询应用聚合功能,可以在查询的任何位置使用filter,例如,仅按员工用户的活动状态对其进行统计:

ELECTis_active,COUNT(id) AS total
FROMauth_user
WHEREis_staff = True
GROUP BYis_active
(User.objects
.values('is_active')
.filter(is_staff=True)
.annotate(total=Count('id')))

如何进行分组排序

filter类似,要对分组结果排序,可以在查询中使用order_by

SELECTis_active,COUNT(id) AS total
FROMauth_user
GROUP BYis_active
ORDER BYis_active,total
(User.objects
.values('is_active')
.annotate(total=Count('id'))
.order_by('is_staff', 'total'))

请注意:你可以按分组的关键词is_active和聚合的关键词total进行排序。

如何联合聚合查询

要生成同分组的多个聚合查询,请添加多个annotation:

SELECTis_active,COUNT(id) AS total,MAX(date_joined) AS last_joined
FROMauth_user
GROUP BYis_active
from django.db.models import Max(User.objects
.values('is_active')
.annotate(total=Count('id'),last_joined=Max('date_joined'),
))

该查询将得到活动用户和非活动用户的数量,以及用户加入每个组的最后日期。

根据多个字段进行分组

就像执行多个聚合一样,我们可能也希望根据多个字段进行分组。例如,按活动状态和人员状态分组:

SELECTis_active,is_staff,COUNT(id) AS total
FROMauth_user
GROUP BYis_active,is_staff
(User.objects
.values('is_active', 'is_staff')
.annotate(total=Count('id')))

此查询的结果包括is_activeis_staff和每个组中的用户数。

根据表达式分组

分组的另一个常见用例是按表达式分组。例如,统计每年加入的用户数:

SELECTEXTRACT('year' FROM date_joined),COUNT(id) AS total
FROMauth_user
GROUP BYEXTRACT('year' FROM date_joined)
(User.objects
.values('date_joined__year')
.annotate(total=Count('id')))

注意,为了从日期开始获取年份,我们在第一次调用values()时使用了特殊表达式<field>__year。查询的结果是一个dict,键的名称将是date_joined__year

有时,内置表达式不够,需要在更复杂的表达式上进行聚合。例如,按注册后登录的用户分组:

SELECTlast_login > date_joined AS logged_since_joined,COUNT(id) AS total
FROMauth_user
GROUP BYlast_login > date_joined
from django.db.models import (ExpressionWrapper,Q, F, BooleanField,
)(User.objects
.annotate(logged_since_joined=ExpressionWrapper(Q(last_login__gt=F('date_joined')),output_field=BooleanField(),)
)
.values('logged_since_joined')
.annotate(total=Count('id'))
.values('logged_since_joined', 'total')

这里的表达式相当复杂。我们首先使用annotate构建表达式,然后在下面对values()的调用中通过引用表达式将其标记为按该关键词分组。后面的代码就跟前述一样了。

根据条件聚合

根据条件,只能对组的一部分进行聚合。当有多个聚合时,条件就很有用了。例如,按注册年份统计员工用户和非员工用户的数量:

SELECTEXTRACT('year' FROM date_joined),COUNT(id) FILTER (WHERE is_staff = True) AS staff_users,COUNT(id) FILTER (WHERE is_staff = False) AS non_staff_usersFROMauth_user
GROUP BYEXTRACT('year' FROM date_joined)
from django.db.models import F, Q(User.objects
.values('date_joined__year')
.annotate(staff_users=(Count('id', filter=Q(is_staff=True))),non_staff_users=(Count('id', filter=Q(is_staff=False))),
))

上面的SQL来自PostgreSQL,它和SQLite是目前唯一支持FILTER语法快捷方式(正式名称为“选择性聚合”)的数据库。对于其他数据库,ORM将使用CASE ... WHEN来代替。

如何使用Having

HAVING子句用于筛选聚合函数的结果。例如,查找超过100多个用户加入的年份:

SELECTis_active,COUNT(id) AS total
FROMauth_user
GROUP BYis_active
HAVINGCOUNT(id) > 100
(User.objects
.annotate(year_joined=F('date_joined__year'))
.values('is_active')
.annotate(total=Count('id'))
.filter(total__gt=100))

annotate中的total查询结果进行过滤,即后面的filter,它与SQL中的HAVING子句等效。

根据Distinct分组

对于某些聚合函数(如“COUNT”),有时只需要计算不同的出现次数。例如,每一种活动状态中的用户有多少不同的姓氏:

SELECTis_active,COUNT(id) AS total,COUNT(DISTINCT last_name) AS unique_names
FROMauth_user
GROUP BYis_active
(User.objects
.values('is_active')
.annotate(total=Count('id'),unique_names=Count('last_name', distinct=True),
))

注意在Count的参数中使用了distinct=True

使用聚合字段创建表达式

聚合字段通常只是解决较大问题的第一步。例如,按用户活动状态列出的唯一姓氏的百分比是多少:

SELECTis_active,COUNT(id) AS total,COUNT(DISTINCT last_name) AS unique_names,(COUNT(DISTINCT last_name)::float/ COUNT(id)::float) AS pct_unique_names
FROMauth_user
GROUP BYis_active
from django.db.models import FloatField
from django.db.models.functions import Cast(User.objects
.values('is_active')
.annotate(total=Count('id'),unique_names=Count('last_name', distinct=True),
)
.annotate(pct_unique_names=(Cast('unique_names', FloatField())/ Cast('total', FloatField())
))

第一个annotate()定义聚合字段。第二个annotate()使用聚合函数构造表达式。

跨表分组

到目前为止,我们只是在一个模型中进行各种数据查询操作,但聚合也能在不同模型(即不同数据库表)之间实现,比较简单的情况是一对一或外键关系。例如,假设我们有一个与用户一一对应的User profile模型,并且我们希望按配置文件的类型统计用户:

SELECTp.type,COUNT(u.id) AS total
FROMauth_user uJOIN user_profile p ON u.id = p.user_id
GROUP BYp.type
(User.objects
.values('user_profile__type')
.annotate(total=Count('id')))')))

就像分组表达式一样,在values中使用关联表,并按该该字段分组。请注意:表示关联数据库包的名称将是user_profile__type

根据多对多关系分组

更复杂的还是多对多的关系。例如,计算每个用户参与了多少个小组:

SELECTu.id,COUNT(ug.group_id) AS memberships
FROMauth_userLEFT OUTER JOIN auth_user_groups ug ON (u.id = ug.user_id)
GROUP BYu.id
(User.objects
.annotate(memberships=Count('groups'))
.values('id', 'memberships'))

用户可以是多个组的成员,要统计用户所属的组数,我们在User模型中使用了相关名称groups。如果未显式设置相关名称(且未显式禁用),Django将自动生成格式为{related model model}_set的名称。例如group_set

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/884162.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java - 数组实现大顶堆

题目描述 实现思路 要实现一个堆&#xff0c;我们首先要了解堆的概念。 堆是一种完全二叉树&#xff0c;分为大顶堆和小顶堆。 大顶堆&#xff1a;每个节点的值都大于或等于其子节点的值。 小顶堆&#xff1a;每个节点的值都小于或等于其子节点的值。 完全二叉树&#xff…

人工智能与数据安全:Facebook如何应对隐私挑战

在数字时代&#xff0c;数据隐私和安全成为了用户和企业关注的核心问题。作为全球最大的社交媒体平台之一&#xff0c;Facebook面临着日益严峻的隐私挑战。近年来&#xff0c;频繁发生的数据泄露事件和对用户隐私的质疑&#xff0c;使得Facebook在保护用户数据方面倍感压力。为…

2024年ABS分区更新,聚焦管理科学领域新动态

2024学术期刊指南简介 2024年10月30日&#xff0c;英国商学院协会&#xff08;Chartered Association of Business Schools&#xff09;发布了最新的《学术期刊指南&#xff08;Academic Journal Guide&#xff09;》&#xff08;以下简称“《指南》”&#xff09;&#xff0c…

解读!中国人工智能大模型技术白皮书!

近期&#xff0c;中国人工智能协会发布了《中国人工智能大模型技术白皮书》&#xff0c;系统梳理了大模型技术演进&#xff0c;深入探讨关键技术要素&#xff0c;并剖析当前挑战及未来展望。我为大家做了简要总结&#xff0c;并附上原文供深入阅读。 目录 第 1 章 大模型技术概…

深度学习笔记之BERT(一)BERT的基本认识

深度学习笔记之BERT——BERT的基本认识 引言回顾&#xff1a;Transformer的策略回顾&#xff1a;Word2vec的策略和局限性 BERT \text{BERT} BERT的基本理念抽象的双向BERT的预训练策略 预训练与微调 引言 从本节开始&#xff0c;将介绍 BERT \text{BERT} BERT系列模型以及其常…

二:Linux学习笔记(第一阶段)-- Linux命令

目录 Linux注意事项&#xff1a; Linux目录 Linux系统基础命令 1. 文件和目录操作 2. 文件查看和编辑 3. 文件权限和所有权 4. 系统信息 5. 网络命令 6. 文件查找 7. 压缩和解压缩 8. 系统管理 Linux注意事项&#xff1a; 严格区分大小写一切皆文件windows下的程序不…

基于 Java 语言双代号网络图自动绘制系统

基于Java语言双代号网络图自动绘制系统研究与实现 一、摘要 网络计划技术已被广泛应用于工业、农业、国防、科学研究等多个领域中的项目计划与管理&#xff0c;以缩短项目周期&#xff0c;提高资源的利用效率。在网络计划技术中&#xff0c;绘制网络图是网络计划技术的基础工…

多模态大模型微调实践!PAI+LLaMA Factory搭建AI导游

一、引言 AI的快速发展推动了各行各业的智能化转型和创新&#xff0c;随之而来的是对AI应用的迫切需求。 如何微调大模型、高效搭建AI应用成为了开发者们广泛关注的技术方向。阿里云人工智能平台PAI&#xff0c;联合开源低代码大模型微调框架LLaMA Factory &#xff0c;共同打…

设计模式-单例模型(单件模式、Singleton)

单例模式是一种创建型设计模式&#xff0c; 让你能够保证一个类只有一个实例&#xff0c; 并提供一个访问该实例的全局节点。 单例模式同时解决了两个问题&#xff0c; 所以违反了单一职责原则&#xff1a; 保证一个类只有一个实例。 为什么会有人想要控制一个类所拥有的实例…

基于SSM+微信小程序的社团登录管理系统(社团1)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 2、项目技术 3、开发环境 4、功能介绍 1、项目介绍 基于SSM微信小程序的社团登录管理系统实现了管理员及社团、用户。 1、管理员实现了首页、用户管理、社团管理、社团信息管理、社…

DAYWEB69 攻防-Java 安全JWT 攻防Swagger 自动化算法签名密匙Druid 泄漏

知识点 1、Java安全-Druid监控-未授权访问&信息泄漏 2、Java安全-Swagger接口-文档导入&联动批量测试 2、Java安全-JWT令牌攻防-空算法&未签名&密匙提取 Java安全-Druid监控-未授权访问&信息泄漏 Druid是阿里巴巴数据库事业部出品&#xff0c;为监控而…

SMO算法 公式推导

min ⁡ α 1 2 ∑ i 1 N ∑ j 1 N α i α j y i y j K ( x i ⋅ x j ) − ∑ i 1 N α i s.t. ∑ i 1 N α i y i 0 0 ≤ α i ≤ C , i 1 , 2 , ⋯ , N (9-69) \begin{aligned} & \min_{\alpha} \quad \frac{1}{2} \sum_{i1}^{N} \sum_{j1}^{N} \alpha_i \alpha_j…

OpenCV系列教程六:信用卡数字识别、人脸检测、车牌/答题卡识别、OCR

文章目录 一、信用卡数字识别1.1 模板匹配1.2 匹配多个对象1.3 处理数字模板1.4 预处理卡片信息&#xff0c;得到4组数字块。1.5 遍历数字块&#xff0c;将卡片中每个数字与模板数字进行匹配 二、人脸检测2.1人脸检测算法原理2.2 OpenCV中的人脸检测流程 三、车牌识别3.1 安装t…

2024年10月总结及随笔之漏更及失而复得

1. 回头看 日更坚持了670天。 读《数据湖仓》更新完成读《数据工程之道&#xff1a;设计和构建健壮的数据系统》开更并持续更新 2023年至2024年10月底累计码字1642797字&#xff0c;累计日均码字2451字。 2024年10月码字86801字&#xff0c;同比下降30.77%&#xff0c;环比…

VScode + PlatformIO 了解

​Visual Studio Code Visual Studio Code&#xff08;简称 VS Code&#xff09;是一款由微软开发且跨平台的免费源代码编辑器。该软件以扩展的方式支持语法高亮、代码自动补全&#xff08;又称 IntelliSense&#xff09;、代码重构功能&#xff0c;并且内置了工具和 Git 版本…

一二三应用开发平台自定义查询设计与实现系列2——查询方案功能实现

查询方案功能实现 上面实现了自定义查询功能框架&#xff0c;从用户角度出发&#xff0c;有些条件组合可以形成特定的查询方案&#xff0c;对应着业务查询场景。诸多查询条件的组合&#xff0c;不能每次都让用户来设置&#xff0c;而是应该保存下来&#xff0c;下次可以直接使…

WebSocket 连接频繁断开的问题及解决方案

文章目录 WebSocket 连接频繁断开的问题及解决方案1. 引言2. 什么是 WebSocket&#xff1f;2.1 WebSocket 的优势2.2 WebSocket 的工作原理 3. WebSocket 连接频繁断开的常见原因3.1 服务器端问题3.1.1 服务器负载过高3.1.2 服务器配置不当3.1.3 超时设置 3.2 网络问题3.2.1 网…

萤石私有化设备视频平台EasyCVR视频融合平台如何构建农业综合监控监管系统?

现代农业的迅速发展中&#xff0c;集成监控管理系统已成为提高农业生产效率和优化管理的关键工具。萤石私有化设备视频平台EasyCVR&#xff0c;作为一个具有高度可扩展性、灵活的视频处理能力和便捷的部署方式的视频监控解决方案&#xff0c;为农业监控系统的建设提供了坚实的技…

#渗透测试#SRC漏洞挖掘# 信息收集-Shodan之搜索语法进阶

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

Fsm3

采用读热码编写方式&#xff1a; module top_module(input clk,input in,input areset,output out); ////reg [3:0]A 4d0001;// reg [3:0]B 4d0010;//reg [3:0]C 4d0100;// reg [3:0]D 4d1000; //1、首先用读热码定义四个状态变量parameter A 4d0001 ,B 4d0010, C 4d01…