目录

  1. 聚合函数概述
  2. 使用 Django ORM 进行聚合查询
  3. 分组查询:annotate
  4. 多表聚合与分组查询
  5. 常见问题与解决方案
  6. 参考资料

1. 聚合函数概述

聚合函数用于计算数据的统计信息,如求和、计数、平均值等。在 Django ORM 中,聚合功能通过 aggregate()annotate() 方法实现。

  • aggregate():返回整个查询集的聚合结果。
  • annotate():对每个模型实例进行聚合,返回每个实例对应的聚合值。

Django ORM 提供了多种常见的聚合函数,包括:

  • Sum:求和
  • Avg:平均值
  • Count:计数
  • Max:最大值
  • Min:最小值

2. 使用 Django ORM 进行聚合查询

2.1 aggregate() 函数

aggregate() 用于对查询集的所有数据进行聚合,返回一个包含聚合结果的字典。常用的聚合函数如 SumCountAvg 等。

示例:计算所有文章的总字数

假设我们有一个 Article 模型,每篇文章有一个 content 字段,存储文章内容。我们可以使用 aggregate() 来计算所有文章的总字数。

from django.db.models import Sum, Count
from myapp.models import Article

# 聚合查询,计算所有文章的总字数
total_words = Article.objects.aggregate(total_content_length=Sum('content_length'))

print(total_words)

这里,content_length 是文章的字符长度(可以通过自定义字段或方法获取),total_content_length 返回一个字典,表示所有文章内容的总长度。

示例:计算文章数量

# 计算所有文章的数量
article_count = Article.objects.aggregate(count=Count('id'))

print(article_count)

Count('id') 会统计 Article 表中所有文章的数量,返回的字典是 {'count': 10}


3. 分组查询:annotate

annotate() 用于对每个模型实例进行聚合计算。与 aggregate() 不同,annotate() 返回的是查询集中的每个对象的聚合值。

3.1 使用 annotate() 进行分组查询

假设我们有 AuthorBook 两个模型,每个作者可以有多本书。我们可以使用 annotate() 来计算每个作者所写书籍的数量。

from django.db.models import Count
from myapp.models import Author

# 查询每个作者写的书籍数量
authors = Author.objects.annotate(book_count=Count('book'))

for author in authors:
    print(f"{author.name} has written {author.book_count} books.")

annotate() 会在 Author 模型实例上计算每个作者对应的书籍数量,book_count 会被添加到每个 Author 实例上。

3.2 使用多个聚合函数

你还可以同时使用多个聚合函数。例如,获取每个作者所写书籍的数量和平均价格。

from django.db.models import Avg

# 查询每个作者写的书籍数量和书籍的平均价格
authors = Author.objects.annotate(
    book_count=Count('book'),
    avg_price=Avg('book__price')
)

for author in authors:
    print(f"{author.name} has written {author.book_count} books with an average price of {author.avg_price}.")

book__priceBook 模型中 price 字段的引用,Avg 会计算每个作者书籍的平均价格。


4. 多表聚合与分组查询

Django ORM 还允许对多个表进行聚合和分组查询。通过外键关系,可以连接相关的表并进行复杂的聚合操作。

4.1 多表聚合:作者与书籍

假设我们有 AuthorBook 两个模型,Book 模型有一个外键字段 author,指向 Author 模型。我们可以查询每个作者所写书籍的总价格和书籍数量。

from django.db.models import Sum, Count

# 查询每个作者所写书籍的数量和总价格
authors = Author.objects.annotate(
    book_count=Count('book'),
    total_price=Sum('book__price')
)

for author in authors:
    print(f"{author.name} has written {author.book_count} books with a total price of {author.total_price}.")

在这个查询中,book__price 通过外键关系访问 Book 表的 price 字段。annotate() 会对每个作者的书籍进行分组并计算数量和总价格。

4.2 多表分组查询:学生与课程

假设我们有 StudentCourse 两个模型,学生和课程之间是多对多关系。我们可以计算每个学生选修的课程数量,并对结果进行排序。

from django.db.models import Count

# 查询每个学生选修的课程数量
students = Student.objects.annotate(course_count=Count('courses')).order_by('-course_count')

for student in students:
    print(f"{student.name} is enrolled in {student.course_count} courses.")

在这个查询中,Count('courses') 会统计每个学生选修的课程数量,并按课程数量降序排列学生。


5. 常见问题与解决方案

1. 聚合和分组查询结果为空

  • 在使用 annotate()aggregate() 时,如果查询集为空,结果也会为空。确保数据表中有相关数据,并检查查询条件是否正确。

2. annotate()aggregate() 的性能问题

  • 聚合操作可能导致性能问题,尤其是在数据量大的情况下。可以使用 select_related()prefetch_related() 来优化查询,减少数据库查询次数。

3. 使用外键字段时出现 DoesNotExist 异常

  • 当查询外键字段时,确保相关的外键记录存在。如果外键记录不存在,Django 会抛出 DoesNotExist 异常。

6. 参考资料

出站链接

站内链接