72.Python中ORM聚合函數詳解:Avg,aggregate,annotate


聚合函數:

如果你用原生SQL語句,則可以使用聚合函數提取數據。比如提取某個商品銷售的數量,那么就可以使用Count,如果想要知道銷售的平均價格,那么就可以使用Avg。
聚合函數是通過aggregate方法來實現的,在講解這些聚合函數的用法的時候,都是基於以下的模型來實現的。

示例代碼如下:

'''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賦值給一個關鍵字參數。
示例代碼如下:

from django.db.models import Avg


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

此時打印出的輸出結果就是:
{"my_avg": 價格}

同時我們可以打印出查詢的原生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表中圖書的數量.

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”字句。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM