python Django中的聚合()与注解()

piv4azn7  于 2023-01-24  发布在  Python
关注(0)|答案(4)|浏览(95)

Django的QuerySet有两个方法,annotateaggregate
与aggregate()不同,annotate()不是一个终止子句。annotate()子句的输出是一个QuerySet。https://docs.djangoproject.com/en/4.1/topics/db/aggregation/#generating-aggregates-for-each-item-in-a-queryset
它们之间还有什么不同吗?如果没有,那么为什么aggregate存在呢?

9jyewag0

9jyewag01#

我将重点介绍示例查询,而不是您从文档中引用的内容。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是书的查询集,但是每本书都被注解了作者的数量。

xxb16uws

xxb16uws2#

    • Aggregate**Aggregate在整个QuerySet上生成结果(摘要)值。Aggregate在行集上操作,以从行集中获取单个值。(例如,行集中所有价格的总和)。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)
    • 在视图中,它将计算每个视频的喜欢次数**
huwehgph

huwehgph3#

这是主要的区别,但是聚合的工作范围也比注解更大。注解与查询集中的单个项有着内在的联系。如果您在多对多字段上运行Count注解,您将获得查询集中每个成员的单独计数(作为一个附加属性)。然而,如果你对聚合做同样的事情,它会试图计算查询集的 * 每个 * 成员上的每个关系,甚至重复的,并将其作为一个值返回。

of1yzvn4

of1yzvn44#

  • aggregate()可以计算模型的列。* 返回字典。
  • annotate()可以计算同一个外键的子模型的id列。
  • 平均值()、计数()、最大值()、最小值()、总和()等可用于aggregate()annotate()

例如,CategoryProduct型号如下:

# "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

下面还有CategoryProduct管理员:

# "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',)

并且,有以下2个类别:

并且,有以下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视图,该视图在aggregate()的Avg()、Count()、Max()、Min()和Sum()中有idcategory_idprice,如下所示:

# "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_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_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_id'), 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_id__max': 2, 'id__sum': 15, 'id__min': 1}
{'price__sum': Decimal('150.00')}
{}

接下来,我将解释annotate()

注解():

现在,我运行test视图,该视图在annotate()中的Count()中具有型号名称product,如下所示。***型号名称product**可以获取Product模型中id列的值:

# "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 columns and functions in different order
        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[0].product__avg, 
        qs[0].product__count, 
        qs[0].product__max, 
        qs[0].product__min, 
        qs[0].product__sum
    )
        
    return HttpResponse("Test")

然后,在控制台上输出以下内容:

<QuerySet [<Category: Food>, <Category: Drink>]>
1 Food 2.0 3 3 1 6
2 Drink 2.0 3 3 1 6

相关问题