[英]aggregate() vs annotate() in Django
Django 的QuerySet
有兩個方法, annotate
和aggregate
。 文件說:
與 aggregate() 不同,annotate() 不是終止子句。 annotate()子句的output是一個QuerySet。 https://docs.djangoproject.com/en/4.1/topics/db/aggregation/#generating-aggregates-for-each-item-in-a-queryset
它們之間還有其他區別嗎? 如果不是,那么aggregate
為什么存在?
我將重點關注示例查詢,而不是文檔中的引用。 Aggregate
計算整個查詢 Aggregate
值。 Annotate
計算查詢集中每個項目的匯總值。
>>> Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35}
返回包含查詢集中所有書籍平均價格的字典。
>>> q = Book.objects.annotate(num_authors=Count('authors'))
>>> q[0].num_authors
2
>>> q[1].num_authors
1
q
是書籍的查詢集,但每本書都注明了作者的數量。
這是主要的區別,但聚合也比注釋更宏大。 注釋本質上與查詢集中的各個項相關。 如果在類似多對多字段的內容上運行Count
注釋,則會為查詢集的每個成員獲取單獨的計數(作為添加的屬性)。 但是,如果要對聚合執行相同操作,它將嘗試計算查詢集的每個成員上的每個關系,即使是重復項,並將其作為一個值返回。
Aggregate Aggregate在整個QuerySet上生成結果(摘要)值。 聚合操作在行集上以從行集中獲取單個值。(例如,行集中所有價格的總和)。 Aggregate應用於整個QuerySet,並在整個QuerySet上生成結果(摘要)值。
在模型中:
class Books(models.Model):
name = models.CharField(max_length=100)
pages = models.IntegerField()
price = models.DecimalField(max_digits=5, decimal_places=3)
在殼牌:
>>> Books.objects.all().aggregate(Avg('price'))
# Above code will give the Average of the price Column
>>> {'price__avg': 34.35}
Annotate Annotate為QuerySet中的每個對象生成一個獨立的摘要。(我們可以說它迭代QuerySet中的每個對象並應用操作)
在模型中:
class Video(models.Model):
name = models.CharField(max_length=52, verbose_name='Name')
video = models.FileField(upload_to=document_path, verbose_name='Upload
video')
created_by = models.ForeignKey(User, verbose_name='Created by',
related_name="create_%(class)s")
user_likes = models.ManyToManyField(UserProfile, null=True,
blank=True, help_text='User can like once',
verbose_name='Like by')
在視圖中:
videos = Video.objects.values('id', 'name','video').annotate(Count('user_likes',distinct=True)
在視圖中,它將計算每個視頻的喜歡
aggregate()可以計算模型的列。 *返回字典。
annotate()可以計算相同外鍵的子模型的id
列。
*Avg() 、Count() 、Max() 、Min() 、Sum()等可以與aggregate()
和annotate()
一起使用。
例如下面有Category
和Product
模型:
# "models.py"
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class Product(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
price = models.DecimalField(decimal_places=2, max_digits=5)
def __str__(self):
return self.name
並且,下面有Category
和Product
管理員:
# "admin.py"
from django.contrib import admin
from .models import Category, Product
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('id', 'name')
ordering = ('id',)
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ('id', 'category_id', 'category', 'name', 'price')
ordering = ('id',)
並且,有以下兩類:
並且,有以下 5 種產品:
並且,下面有test
視圖:
# "views.py"
from .models import Category, Product
from django.http import HttpResponse
from django.db.models import Avg
from django.db.models import Count
from django.db.models import Max
from django.db.models import Min
from django.db.models import Sum
def test(request):
return HttpResponse("Test")
首先,我解釋一下aggregate()
。
現在,我運行test
視圖,該視圖在Avg() 、Count() 、Max() 、Min()和Sum()中具有列id
、 category_id
和price
在aggregate()
中,如下所示:
# "views.py"
# ...
def test(request):
print(Product.objects.aggregate(Avg('id')))
print(Product.objects.aggregate(Count('id')))
print(Product.objects.aggregate(Max('id')))
print(Product.objects.aggregate(Min('id')))
print(Product.objects.aggregate(Sum('id')))
print()
print(Product.objects.aggregate(Avg('category')))
print(Product.objects.aggregate(Count('category')))
print(Product.objects.aggregate(Max('category')))
print(Product.objects.aggregate(Min('category')))
print(Product.objects.aggregate(Sum('category')))
print()
print(Product.objects.aggregate(Avg('category_id')))
print(Product.objects.aggregate(Count('category_id')))
print(Product.objects.aggregate(Max('category_id')))
print(Product.objects.aggregate(Min('category_id')))
print(Product.objects.aggregate(Sum('category_id')))
print()
print(Product.objects.aggregate(Avg('price')))
print(Product.objects.aggregate(Count('price')))
print(Product.objects.aggregate(Max('price')))
print(Product.objects.aggregate(Min('price')))
print(Product.objects.aggregate(Sum('price')))
return HttpResponse("Test")
然后,以下這些詞典在控制台上輸出:
{'id__avg': 3.0}
{'id__count': 5}
{'id__max': 5}
{'id__min': 1}
{'id__sum': 15}
{'category__avg': 1.4}
{'category__count': 5}
{'category__max': 2}
{'category__min': 1}
{'category__sum': 7}
{'category_id__avg': 1.4}
{'category_id__count': 5}
{'category_id__max': 2}
{'category_id__min': 1}
{'category_id__sum': 7}
{'price__avg': Decimal('30.0000000000000000')}
{'price__count': 5}
{'price__max': Decimal('50.00')}
{'price__min': Decimal('10.00')}
{'price__sum': Decimal('150.00')}
並且, aggregate()
可以接受任意順序的多種列和函數,多個相同類型的列和函數以及沒有列和函數,如下所示。 *多個相同類型的列和函數的多個相同結果合並為一個結果,沒有列和函數得到一個空字典:
# "views.py"
# ...
def test(request):
# Multiple kinds of columns and functions in any order
print(
Product.objects.aggregate(
Max('price'), Max('category'), Sum('id'), Min('id')
)
)
# The multiple same kind of columns and functions
print(
Product.objects.aggregate(
Sum('price'), Sum('price'), Sum('price')
)
)
# No columns and functions
print(Product.objects.aggregate())
return HttpResponse("Test")
然后,以下這些詞典在控制台上輸出:
{'price__max': Decimal('50.00'), 'category__max': 2, 'id__sum': 15, 'id__min': 1}
{'price__sum': Decimal('150.00')}
{}
並且,下面的Max()
和Min()
可以接受非數字類型:
# "views.py"
# ...
def test(request):
print(Product.objects.aggregate(Max('name')))
print(Product.objects.aggregate(Min('name')))
return HttpResponse("Test")
然后,以下這些詞典在控制台上輸出:
{'name__max': 'Tea'}
{'name__min': 'Apple'}
但是,下面的Avg()
、 Count()
和Sum()
不能接受非數字類型:
# "views.py"
# ...
def test(request):
print(Product.objects.aggregate(Avg('name')))
print(Product.objects.aggregate(Count('name')))
print(Product.objects.aggregate(Sum('name')))
return HttpResponse("Test")
因此,會出現以下錯誤:
django.db.utils.ProgrammingError:function avg(字符變化)不存在
django.db.utils.ProgrammingError:function 總和(字符變化)不存在
django.db.utils.ProgrammingError:function 總和(字符變化)不存在
並且,您可以更改默認鍵名,如下所示:
# "views.py"
# ...
def test(request):
print(Product.objects.aggregate(priceAve=Avg('price')))
print(Product.objects.aggregate(priceCount=Count('price')))
print(Product.objects.aggregate(priceMax=Max('price')))
print(Product.objects.aggregate(priceMin=Min('price')))
print(Product.objects.aggregate(priceSum=Sum('price')))
return HttpResponse("Test")
然后,默認鍵名更改如下所示:
{'priceAve': Decimal('30.0000000000000000')}
{'priceCount': 5}
{'priceMax': Decimal('50.00')}
{'priceMin': Decimal('10.00')}
{'priceSum': Decimal('150.00')}
接下來,我解釋一下annotate()
。
現在,我在annotate()
中的Count()
中運行具有model 名稱product
的test
視圖,如下所示。 * model name product
可以獲取Product
model 中id
列的值,需要將__avg
, __count
, __max
, __min
和__sum
product
for Avg()
, Count()
, Max()
, Min()
和Sum()
分別是:
# "views.py"
# ...
def test(request):
qs = Category.objects.annotate(Avg('product'))
print(qs)
print(qs[0].id, qs[0].name, qs[0].product__avg)
print(qs[1].id, qs[1].name, qs[1].product__avg)
qs = Category.objects.annotate(Count('product'))
print(qs)
print(qs[0].id, qs[0].name, qs[0].product__count)
print(qs[1].id, qs[1].name, qs[1].product__count)
qs = Category.objects.annotate(Max('product'))
print(qs)
print(qs[0].id, qs[0].name, qs[0].product__max)
print(qs[1].id, qs[1].name, qs[1].product__max)
qs = Category.objects.annotate(Min('product'))
print(qs)
print(qs[0].id, qs[0].name, qs[0].product__min)
print(qs[1].id, qs[1].name, qs[1].product__min)
qs = Category.objects.annotate(Sum('product'))
print(qs)
print(qs[0].id, qs[0].name, qs[0].product__sum)
print(qs[1].id, qs[1].name, qs[1].product__sum)
return HttpResponse("Test")
然后,在控制台上輸出以下內容:
<QuerySet [<Category: Food>, <Category: Drink>]>
1 Food 2.0 # Average "id" column in "Product" model whose row's foreign key is "1" of "Food"
2 Drink 4.5 # Average "id" column in "Product" model whose row's foreign key is "2" of "Drink"
<QuerySet [<Category: Food>, <Category: Drink>]>
1 Food 3 # Count "id" in "Product" model whose row's foreign key is "1" of "Food"
2 Drink 2 # Count "id" in "Product" model whose row's foreign key is "2" of "Drink"
<QuerySet [<Category: Food>, <Category: Drink>]>
1 Food 3 # Get the highest "id" from "id" column in "Product" model whose row's foreign key is "1" of "Food"
2 Drink 5 # Get the highest "id" from "id" column in "Product" model whose row's foreign key is "2" of "Drink"
<QuerySet [<Category: Food>, <Category: Drink>]>
1 Food 1 # Get the lowest "id" from "Product" model's "id" column whose row's foreign key is "1" of "Food"
2 Drink 4 # Get the lowest "id" from "Product" model's "id" column whose row's foreign key is "2" of "Drink"
<QuerySet [<Category: Food>, <Category: Drink>]>
1 Food 6 # Sum "id" column in "Product" model whose row's foreign key is "1" of "Food"
2 Drink 9 # Sum "id" column in "Product" model whose row's foreign key is "2" of "Drink"
並且, annotate()
可以接受多種函數,如下所示:
# "views.py"
# ...
def test(request):
# Multiple kinds of functions
qs = Category.objects.annotate(
Avg('product'),
Count('product'),
Max('product'),
Min('product'),
Sum('product')
)
print(qs)
print(
qs[0].id, qs[0].name,
qs[0].product__avg,
qs[0].product__count,
qs[0].product__max,
qs[0].product__min,
qs[0].product__sum
)
print(
qs[1].id, qs[1].name,
qs[1].product__avg,
qs[1].product__count,
qs[1].product__max,
qs[1].product__min,
qs[1].product__sum
)
return HttpResponse("Test")
然后,在控制台上輸出以下內容:
<QuerySet [<Category: Food>, <Category: Drink>]>
1 Food 2.0 3 3 1 6
2 Drink 4.5 2 5 4 9
而且,下面的annotate()
沒有product
和product_id
屬性:
# "views.py"
# ...
def test(request):
qs = Category.objects.annotate(
Avg('product'),
Count('product'),
Max('product'),
Min('product'),
Sum('product')
)
print(qs[0].product) # Here
print(qs[1].product_id) # Here
return HttpResponse("Test")
因此,會出現以下錯誤:
AttributeError: 'Category' object 沒有屬性 'product'
AttributeError: 'Category' object 沒有屬性 'product_id'
並且,下面的空annotate()
具有id
和name
屬性:
# "views.py"
# ...
def test(request):
qs = Category.objects.annotate() # Empty "annotate()"
print(qs[0].id, qs[0].name) # Here
print(qs[1].id, qs[1].name) # Here
return HttpResponse("Test")
然后,在控制台上輸出以下內容:
1 Food
2 Drink
但是,下面的空annotate()
沒有product__avg
、 product__count
、 product__max
、 product__min
和product__sum
屬性:
# "views.py"
# ...
def test(request):
qs = Category.objects.annotate() # Empty "annotate()"
print(
qs[0].product__avg, # Here
qs[0].product__count, # Here
qs[0].product__max, # Here
qs[0].product__min, # Here
qs[0].product__sum # Here
)
print(
qs[1].product__avg, # Here
qs[1].product__count, # Here
qs[1].product__max, # Here
qs[1].product__min, # Here
qs[1].product__sum # Here
)
return HttpResponse("Test")
因此,會出現以下錯誤:
AttributeError: 'Category' object 沒有屬性 'product__avg'
AttributeError: 'Category' object 沒有屬性 'product__count'
AttributeError: 'Category' object 沒有屬性 'product__max'
AttributeError: 'Category' object 沒有屬性 'product__min'
AttributeError: 'Category' object 沒有屬性 'product__sum'
並且,您可以更改默認屬性名稱,如下所示:
# "views.py"
# ...
def test(request):
qs = Category.objects.annotate(productAvg=Avg('product'))
print(qs)
print(qs[0].id, qs[0].name, qs[0].productAvg)
print(qs[1].id, qs[1].name, qs[1].productAvg)
qs = Category.objects.annotate(productCount=Count('product'))
print(qs)
print(qs[0].id, qs[0].name, qs[0].productCount)
print(qs[1].id, qs[1].name, qs[1].productCount)
qs = Category.objects.annotate(productMax=Max('product'))
print(qs)
print(qs[0].id, qs[0].name, qs[0].productMax)
print(qs[1].id, qs[1].name, qs[1].productMax)
qs = Category.objects.annotate(productMin=Min('product'))
print(qs)
print(qs[0].id, qs[0].name, qs[0].productMin)
print(qs[1].id, qs[1].name, qs[1].productMin)
qs = Category.objects.annotate(productSum=Sum('product'))
print(qs)
print(qs[0].id, qs[0].name, qs[0].productSum)
print(qs[1].id, qs[1].name, qs[1].productSum)
return HttpResponse("Test")
然后,在控制台上輸出以下內容:
<QuerySet [<Category: Food>, <Category: Drink>]>
1 Food 2.0
2 Drink 4.5
<QuerySet [<Category: Food>, <Category: Drink>]>
1 Food 3
2 Drink 2
<QuerySet [<Category: Food>, <Category: Drink>]>
1 Food 3
2 Drink 5
<QuerySet [<Category: Food>, <Category: Drink>]>
1 Food 1
2 Drink 4
<QuerySet [<Category: Food>, <Category: Drink>]>
1 Food 6
2 Drink 9
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.