72.Python中ORM聚合函数详解:Avg,aggregate,annotate

聚合函数:

若是你用原生SQL语句,则可使用聚合函数提取数据。好比提取某个商品销售的数量,那么就可使用Count,若是想要知道销售的平均价格,那么就可使用Avg。
聚合函数是经过aggregate方法来实现的,在讲解这些聚合函数的用法的时候,都是基于如下的模型来实现的。

示例代码以下:python

'''python
#模型要放在app当中。因此首先要在终端命令行窗口,执行命令:
python manage.py startapp front
同时要将新建立的app添加到settings.py文件中的INSTALLED_APPS变量中。
同时要配置彻底pycharm和数据库的链接信息。
settings.py文件中示例代码以下:
DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'orm_aggregate_demo',
    'USER': 'root',
    'PASSWORD': 'root',
    'HOST': '127.0.0.1',
    'PORT': '3306',
    }
}
models.py文件中示例代码以下:
from django.db import models
# 定义做者的模型
class Author(models.Model):
<!-- 指定unique=True,规定字段的惟一性 -->
    name = models.CharField(max_length=30, unique=True)
    age = models.IntegerField()
    email = models.EmailField()

    class Meta:
        db_table = 'author'

# 定义出版社模型
class Publisher(models.Model):
<!-- 指定unique=True,规定字段的惟一性 -->
    name = models.CharField(max_length=100, unique=True)

    class Meta:

        db_table = 'publisher'


# 定义一个图书模型
class Book(models.Model):
<!-- 指定unique=True,规定字段的惟一性 -->
    name = models.CharField(max_length=100, unique=True)
    pages = models.IntegerField()
    price = models.FloatField()
    rating = models.FloatField()
    author = models.ForeignKey('Author', on_delete=models.CASCADE)
    publisher = models.ForeignKey('Publisher', on_delete=models.CASCADE)

    class Meta:
        db_table = 'book'


# 定义一个预约书的模型
class BookOrder(models.Model):
    book = models.ForeignKey('Book', on_delete=models.CASCADE)
    price = models.FloatField()

    class Meta:
        db_table = 'book_order'


终端命令行窗口,执行命令:python manage.py makemigrations(生成相应的迁移脚本)和python manage.py migrate(将生成的迁移脚本映射到数据库中。)

1.aggregate()方法:

1. Avg:求平均值函数,若是想要获取图书的价格平均值,那么就可使用如下代码实现:

导入模型

from .models import Book
from django.db.models import Avg
from django.http import HttpResponse
# views.py文件中:
def index(request):
    # 聚合函数要放在aggregate()方法中,还有其余的可以执行聚合函数的方法,以后会进行讲解
    result = Book.objects.aggregate(Avg('price'))
    print(result)

此时打印出的输出结果就是:
{"price__avg": 价格}
“price__avg”是根据field__avg规则构成的,若是想要修改默认的名字,那么能够将Avg赋值给一个关键字参数。
示例代码以下:mysql

from django.db.models import Avg


    result = Book.objects.aggregate(my_avg=Avg('price'))
    print(result)

此时打印出的输出结果就是:
{"my_avg": 价格}sql

同时咱们能够打印出查询的原生SQL语句数据库

from django.db import connection


def inex(request):
    result = Book.objects.aggregate(Avg('price'))
    print(connection.queries)
    # queries中存储了不少的SQL语句。
    # 不可以经过print(result.query),进行打印SQL语句。
    # 由于result为dict类型,没有query属性。
    print(type(result))
1.全部聚合函数都是放在'django.db.models'下面。
2.聚合函数不可以够单独执行,必须放在可以执行聚合函数的方法中去执行,好比“aggregate()”方法。
3.在执行聚合函数的时候,会给这个聚合函数取个名字,取名字的规则,默认是“field__聚合函数名”。若是不想使用默认的名字,能够在执行聚合函数的时候传递进去关键字参数,示例代码以下:
result = Book.objects.aggregate(avg=Avg("price"))
4.若是想要查看执行查询操做的sql语句的话,就要导入connection了,由于执行aggregate()方法返回的是字典类型的值,可是若是想要调用query查看原生sql语句的话,执行调用的对象必须是QuerySet类型的对象,而字典没有query属性。可是咱们能够经过django.db import connection,进而就能够调用connection.queries。示例代码以下:
from django.db import connection
from .models import Book
from django.http import HttpResponse
from django.db.models import Avg

    
def index(request):
    result = Book.objects.aggregate(Avg('price'))
    print(connection.queries)
    return HttpResponse("success!")

2. Count:获取指定对象的个数,示例代码以下:

导入模型

result = Book.objects.aggregate(book_num=Count('id'))

此时就会返回Book表中图书的数量.django

3.annotate()方法:

from django.shortcuts import render
from django.http import HttpResponse
from .models import Author,Publisher,Book,BookOrder
from django.db.models import Avg,Count,Sum
from django.db import connection


def index(request):
# 计算同一种书的预约平均价格,使用annotate()方法执行聚合函数,能够进行分组(group by)
# 由父类和子类的模型关系咱们知道,子类经过外键的关系了父类,那么django就会在底层为父类添加一个名为子类名字小写形式的方法。
     books = Book.objects.annotate(avg=Avg("bookorder__price"))
    # print(books)
    # 打印出结果:<QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (4)>]>
    # 结果显示的是QuerySet类型,能够经过遍历获得具体的图书相关信息
    for book in books:
        print("%s,%s,平均价格:%s" % (book.name,book.author,book.avg))
    # 打印出结果:
    # 三国演义,罗贯中,47,312587329@qq.com,平均价格:101.5
    # 水浒传,施耐庵,57,1924572@qq.com,平均价格:107.5
    # 红楼梦,曹雪芹,42,123521472@qq.com,平均价格:102.0
    # 西游记,吴承恩,34,193452272@qq.com,平均价格:None

    print(connection.queries)
    # 打印出结果:[{'sql': 'SELECT @@SQL_AUTO_IS_NULL', 'time': '0.000'}, {'sql': 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', 'time': '0.000'}, {'sql': 'SELECT `book`.`id`, `book`.`name`, `book`.`pages`, `book`.`price`, `book`.`rating`, `book`.`author_id`, `book`.`publisher_id`, AVG(`book_order`.`price`) AS `avg` FROM `book` LEFT OUTER JOIN `book_order` ON (`book`.`id` = `book_order`.`book_id`) GROUP BY `book`.`id` ORDER BY NULL LIMIT 21', 'time': '0.000'}]

    return HttpResponse("success !")

aggregate和annotate的区别:

1.aggregate:返回的是字典类型的数据,默认状况下,键名为聚合函数操做的字段名__聚合函数名,键所对应的值就是聚合函数返回的值了。可是aggregate()方法不会返回QuerySet。
2.annotate:在原来模型的基础上欠佳一个使用了聚合函数的字段,而且在使用聚合函数的时候,会使用当前这个模型的主键进行分组(group by)。若是在求图书的销售总额的话,那么将在每条图书的数据上都添加一个字段叫作total,计算这本书的销售总额。而若是使用的是aggregate,那么将求出全部图书的销售总额。
其中,aggregate()方法返回的是一个字典,字典中的值就是执行聚合函数的值,而annotate()方法返回的是一个“QuerySet”对象,而且会在查找的模型上添加一个聚合函数的属性。annotate()方法会使用“group by”字句进行分组,只有调用了“group by”字句,才能对每一条数据求聚合函数的值。而aggregate()方法不能调用“group by”字句。
相关文章
相关标签/搜索