Django 聚合查询及使用步骤

 更新时间:2024年09月23日 10:53:28   作者:拾伍廿肆  
本文详细介绍了Django中聚合查询的使用方法和步骤,包括aggregate()和annotate()两种聚合查询方式,以及F()和Q()查询的使用场景,文中通过具体代码示例解释了如何在Django项目中实现数据聚合,感兴趣的朋友跟随小编一起看看吧

一、聚合查询

使用聚合查询前要先从 django.db.models 引入 Avg、Max、Min、Count、Sum(首字母大写)
聚合查询返回值的数据类型是字典

聚合查询使用aggregate()对查询集执行聚合操作,它允许我们使用数据库提供的聚合函数(如 COUNT(), AVG(), SUM(), MAX(), MIN() 等)来对查询集中的数据进行汇总计算,aggregate() 方法返回一个字典,字典的键是你指定的聚合函数别名,值是聚合计算的结果

queryset.aggregate(聚合函数)
# 别名使用
queryset.aggregate(别名 = 聚合函数名("属性名称"))
# 例:
result = Book.objects.aggregate(average_price=Avg('price'), total_books=Count('id'))
# 结果示例: {'average_price': 100.25, 'total_books': 150}

二、使用步骤

1.准备工作

还是之前那个fa的项目目录,在views.py内引入

# 导入聚合函数
from django.db.models import Avg,Max,Min,Count,Sum

在models.py里面,定义一个Book模型

class Book(models.Model):
    title = models.CharField(max_length=255)  # 书名
    author = models.CharField(max_length=255)  # 作者
    price = models.DecimalField(max_digits=10, decimal_places=2)  # 价格
    rating = models.FloatField()  # 评分
    published_date = models.DateField()  # 出版日期
    pages = models.IntegerField()  # 页数
    def __str__(self):
        return self.title

在数据库生成book表,执行下列命令

python manage.py makemigrations
python manage.py migrate

这个时候我们就有一张book的表了,我们自己手动塞入一些数据(这里就不做新增了),然后在下一步实现聚合函数的使用
随意添加的数据

2.具体使用

定义一个方法去使用聚合函数,我们在views.py里面添加一个方法

def getBookSomeInfo(request):
    # 计算书的平均价格
    average_price = models.Book.objects.aggregate(avg_price = Avg('price'))
    # 如果不加别名结果为: {'price__avg': 100.25}
    # 获取书的最高价格
    max_price = models.Book.objects.aggregate(Max('price'))
    # 获取书的最低价格
    min_price = models.Book.objects.aggregate(min_price = Min('price'))
    # 统计书的总数量
    # book_count = models.Book.objects.aggregate(Count('id'))
    book_count = models.Book.objects.aggregate(book_count = Count('id'))
    # 其实也可以使用 len(models.Book.objects.all()) / models.Book.objects.count()
    # 计算所有书的总价格
    total_price = models.Book.objects.aggregate(total_price = Sum('price'))
    return HttpResponse(f"平均价格: {average_price}, 最高价格: {max_price}, 最低价格: {min_price}, 总数量: {book_count}, 总价格: {total_price}")

在路由urls.py里面添加

    path('getBookSomeInfo', views.getBookSomeInfo, name='getBookSomeInfo'),

访问链接http://127.0.0.1:8082/article/getBookSomeInfo

3.分组查询(annotate)

1.定义

annotate() 是 Django ORM 提供的一个方法,用于在查询集中为每个对象添加计算值。与 aggregate() 方法不同,annotate() 是逐个对象进行计算,而 aggregate() 是对整个查询集进行计算,并返回一个汇总结果

2.使用

使用前要先从 django.db.models 引入聚合函数,annotate() 方法接受一个或多个聚合函数作为参数,这些聚合函数会被应用到查询集中,并将结果作为额外字段添加到每个对象上

queryset.annotate(聚合函数)

3.具体案例

我们先修改一下刚刚定义的Book模型,同时增加一个作者User模型

class User(models.Model):
    name = models.CharField(max_length=255)  # 作者名称
    def __str__(self):
        return self.name
class Book(models.Model):
    title = models.CharField(max_length=255)  # 书名
    # author = models.CharField(max_length=255)  # 作者
    user = models.ForeignKey(User, related_name='books', null=True, on_delete=models.CASCADE)  # 作者
    price = models.DecimalField(max_digits=10, decimal_places=2)  # 价格
    rating = models.FloatField()  # 评分
    published_date = models.DateField()  # 出版日期
    pages = models.IntegerField()  # 页数
    def __str__(self):
        return self.title

执行命令生成数据表,user表和book表都先手动写入数据,不通过程序写入数据
views.py增加方法

def getBookFormUser(request):
    # 计算每个作者的书籍数量
    # 这里的 'books' 是 models.User 类中定义的外键名称,如果外键名称不是 'books' 则需要修改
    users_with_book_count = models.User.objects.annotate(book_count = Count('books'))
    users_with_book_count_str = ''
    # 输出每个作者的书籍数量
    for user in users_with_book_count:
        users_with_book_count_str += f"{user.name} has {user.book_count} books.\n"
    # 计算每个作者的书籍平均价格
    # books__price 代表 books 外键的 price 字段
    users_with_avg_price = models.User.objects.annotate(avg_price = Avg('books__price'))
    users_with_avg_price_str = ''
    # 输出每个作者的书籍平均价格
    for user in users_with_avg_price:
        users_with_avg_price_str += f"{user.name} has an average book price of {user.avg_price}.\n"
    # 计算每个作者的书籍总价格和最高评分
    users_with_totals = models.User.objects.annotate(total_price = Sum('books__price'), highest_rating = Max('books__rating'))
    users_with_totals_str = ''
    # 输出每个作者的书籍总价格和最高评分
    for user in users_with_totals:
        users_with_totals_str += f"{user.name} has a total book price of {user.total_price} and the highest rating is {user.highest_rating}.\n"
    # 返回带有换行符的 HTML 响应,确保编码为UTF-8
    return HttpResponse(
        f"每个作者的书籍数量: <br>{users_with_book_count_str}<br>"
        f"每个作者的书籍平均价格: <br>{users_with_avg_price_str}<br>"
        f"每个作者的书籍总价格和最高评分: <br>{users_with_totals_str}",
        content_type="text/html; charset=utf-8"
    )

增加路由

path('getBookFormUser', views.getBookFormUser, name='getBookFormUser'),

访问链接http://127.0.0.1:8000/article/getBookFormUser

4.F() 查询

1.定义

F() 表达式用于在数据库中直接引用字段的值,而不是将值从数据库取出后再进行计算。它允许你在数据库层面进行原子性的计算操作,从而避免出现竞争条件或数据不同步的问题,常用于以下场景:

对字段值进行加减、乘除等数学运算。
比较同一个模型中不同字段的值。
更新字段时直接使用该字段的当前值。

2.使用

要使用 F() 表达式,你需要从 django.db.models 中导入 F 类

from django.db.models import F

字段值的更新(如:增加浏览数)

先更新一下Book模型

class Book(models.Model):
    title = models.CharField(max_length=255)  # 书名
    # author = models.CharField(max_length=255)  # 作者
    user = models.ForeignKey(User, related_name='books', null=True, on_delete=models.CASCADE)  # 作者
    price = models.DecimalField(max_digits=10, decimal_places=2)  # 价格
    rating = models.FloatField()  # 评分
    published_date = models.DateField()  # 出版日期
    pages = models.IntegerField()  # 页数
    views = models.IntegerField(default=0)  # 浏览量
    def __str__(self):
        return self.title

定义方法和路由

def addViews(request):
    # 增加阅读量
    article_id = 1
    models.Book.objects.filter(id=article_id).update(views=F('views') + 1)
    return HttpResponse('Views added successfully')
path('addViews', views.addViews, name='addViews'),

访问链接http://127.0.0.1:8000/article/addViews

一些其他场景
定义方法和路由

def someOtherInfo(request):
    # 比较同一个模型的两个字段的值
    # 获取 price 大于 discount_price 的商品,这个查询会返回所有 price 大于 discount_price 的 Product 实例
    # 注意:F() 函数用于引用其他字段的值,不能用于直接比较两个字段的值,price和views都是字段名
    book_gt_discount = models.Book.objects.filter(price__gt=F('views'))
    book_gt_discount_str = ''
    for item in book_gt_discount:
        book_gt_discount_str += f"Book {item.id} has a price of {item.price} and views of {item.views}\n"
    # 多字段运算
    # 获取所有books的总价格和评分的乘积
    # 使用 F() 表达式在 annotate 中
    books = models.Book.objects.annotate(total_price=F('price') * F('views'))
    str_books = ''
    for item in books:
        str_books += f"Book {item.id} has total price {item.total_price}\n"
    # 查询时对字段进行运算
    # 获取book的价格大于其views加500的书籍
    high_books = models.Book.objects.filter(price__gt=F('views') + 500.00)
    high_books_str = ''
    for item in high_books:
        high_books_str += f"Book {item.id} has a price of {item.price}\n"
    return HttpResponse(
        f"book_gt_discount: <br>{book_gt_discount_str}<br>"
        f"str_books: <br>{str_books}<br>"
        f"high_books_str: <br>{high_books_str}",
        content_type="text/html; charset=utf-8"
    )
path('someOtherInfo', views.someOtherInfo, name='someOtherInfo'),

访问链接http://127.0.0.1:8000/article/someOtherInfo

5.Q() 查询

1.定义

Q() 对象来自 django.db.models,用于创建复杂的查询条件。你可以使用它来结合多个条件,执行与(AND)或或(OR)操作,甚至是非(NOT)操作,尤其是在需要执行“OR”操作或者需要多个条件组合时非常有用。Q() 对象使得构建复杂的查询变得更加灵活和强大,
使用前还是先导入

from django.db.models import Q

2.查询

定义方法和路由

def searchByq(request):
    # 按价格和阅读量查询书籍
    # 注意:Q() 函数用于构建复杂的查询条件,可以与其他条件组合使用
    # 这里的 Q() 函数与 price__gt 条件组合使用,表示价格大于 500.00
    # 与 views__gt 条件组合使用,表示阅读量大于 1
    books_and = models.Book.objects.filter(Q(price__gt=500.00) & Q(views__gt=1))
    books_and_str = ''
    for item in books_and:
        books_and_str += f"Book {item.id} has a price of {item.price} and views of {item.views}\n"
    # 按价格或阅读量查询书籍
    # 这里的 Q() 函数与 price__gt 条件组合使用,表示价格大于 500.00
    # 与 views__gt 条件组合使用,表示阅读量大于 1
    books_or = models.Book.objects.filter(Q(price__gt=500.00) | Q(views__gt=1))
    books_or_str = ''
    for item in books_or:
        books_or_str += f"Book {item.id} has a price of {item.price} and views of {item.views}\n"
    # 按价格范围查询书籍
    # 这里的 Q() 函数与 price__range 条件组合使用,表示价格在 500.00 到 1000.00 之间
    books_range = models.Book.objects.filter(Q(price__range=(500.00, 1000.00)))
    books_range_str = ''
    for item in books_range:
        books_range_str += f"Book {item.id} has a price of {item.price}\n"
    # not 查询 这里使用的 ~Q() 函数表示价格不大于 500.00
    books_not = models.Book.objects.filter(~Q(price__gt=500.00))
    books_not_str = ''
    for item in books_not:
        books_not_str += f"Book {item.id} has a price of {item.price}\n"
    return HttpResponse(
        f"books_and_str: <br>{books_and_str}<br>"
        f"books_or_str: <br>{books_or_str}<br>"
        f"books_range_str: <br>{books_range_str}"
        f"books_not_str: <br>{books_not_str}",
        content_type="text/html; charset=utf-8"
    )
    path('searchByq', views.searchByq, name='searchByq'),

访问链接http://127.0.0.1:8000/article/searchByq

到此这篇关于Django 聚合查询的文章就介绍到这了,更多相关Django 聚合查询内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 在Django中预防CSRF攻击的操作

    在Django中预防CSRF攻击的操作

    这篇文章主要介绍了在Django中预防CSRF攻击的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-03-03
  • python分布式库celery处理大规模的任务并行化

    python分布式库celery处理大规模的任务并行化

    Python中的分布式任务队列时,Celery是一个备受推崇的工具,它是一个功能强大的分布式系统,可用于处理大规模的任务并行化,本文将介绍Celery的基本概念、用法和示例代码,帮助读者更好地了解和使用这个库
    2024-01-01
  • python shutil操作文件实例讲解

    python shutil操作文件实例讲解

    在本篇文章里小编给大家整理了一篇关于python shutil操作文件实例讲解内容,有兴趣的朋友们可以学习下。
    2021-03-03
  • Python中运算符

    Python中运算符"=="和"is"的详解

    大家都知道python中有很多的运算符,今天我们就来深入的介绍is和==这两种运算符以及他们的区别,有需要的朋友们可以参考借鉴,下面来一起看看吧。
    2016-10-10
  • Python 数据筛选功能实现

    Python 数据筛选功能实现

    这篇文章主要介绍了Python 数据筛选,无论是在数据分析还是数据挖掘的时候,数据筛选总会涉及到,这里我总结了一下python中列表,字典,数据框中一些常用的数据筛选的方法,需要的朋友可以参考下
    2023-04-04
  • Pyqt5 关于流式布局和滚动条的综合使用示例代码

    Pyqt5 关于流式布局和滚动条的综合使用示例代码

    这篇文章主要介绍了Pyqt5 关于流式布局和滚动条的综合使用示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • python3.8动态人脸识别的实现示例

    python3.8动态人脸识别的实现示例

    这篇文章主要介绍了python3.8动态人脸识别的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • python实现修改xml文件内容

    python实现修改xml文件内容

    这篇文章主要介绍了python实现修改xml文件内容,XML 指可扩展标记语言,是一种标记语言,是从标准通用标记语言(SGML)中简化修改出来的
    2022-07-07
  • Pytorch中关于BatchNorm2d的参数解释

    Pytorch中关于BatchNorm2d的参数解释

    这篇文章主要介绍了Pytorch中关于BatchNorm2d的参数解释,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • pycharm实现在虚拟环境中引入别人的项目

    pycharm实现在虚拟环境中引入别人的项目

    这篇文章主要介绍了pycharm实现在虚拟环境中引入别人的项目,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-03-03

最新评论