Django 中的aggregate() 与 annotate()

发布于 2024-12-13 10:20:37 字数 493 浏览 3 评论 0 原文

Django 的QuerySet 有两个方法,annotateaggregate。文档说:

与aggregate()不同,annotate()不是终止子句。 annotate() 子句的输出是一个查询集。 https: //docs.djangoproject.com/en/4.1/topics/db/aggregation/#generate-aggregates-for-each-item-in-a-queryset

它们之间还有其他区别吗?如果不是,那为什么会有aggregate存在呢?

Django's QuerySet has two methods, annotate and aggregate. The documentation says that:

Unlike aggregate(), annotate() is not a terminal clause. The output of the annotate() clause is a QuerySet.
https://docs.djangoproject.com/en/4.1/topics/db/aggregation/#generating-aggregates-for-each-item-in-a-queryset

Is there any other difference between them? If not, then why does aggregate exist?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

余生再见 2024-12-20 10:20:37

我会关注示例查询而不是文档中的引用。 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是书籍的查询集,但每本书都标注了作者数量。

I would focus on the example queries rather than your quote from the documentation. Aggregate calculates values for the entire queryset. Annotate calculates summary values for each item in the queryset.

Aggregation

>>> Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35}

Returns a dictionary containing the average price of all books in the queryset.

Annotation

>>> q = Book.objects.annotate(num_authors=Count('authors'))
>>> q[0].num_authors
2
>>> q[1].num_authors
1

q is the queryset of books, but each book has been annotated with the number of authors.

时光沙漏 2024-12-20 10:20:37

聚合
聚合整个查询集的生成结果(摘要)值。
对行集进行聚合操作以从行集中获取单个值。(例如行集中所有价格的总和)。聚合应用于整个查询集,并在整个查询集中生成结果(摘要)值。

在模型中:

class Books(models.Model):
    name = models.CharField(max_length=100)
    pages = models.IntegerField()
    price = models.DecimalField(max_digits=5, decimal_places=3)

在 Shell 中:

>>> Books.objects.all().aggregate(Avg('price'))
# Above code will give the Average of the price Column 
>>> {'price__avg': 34.35}

注释
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
Aggregate generate result (summary) values over an entire QuerySet.
Aggregate operate over the rowset to get a single value from the rowset.(For example sum of all prices in the rowset). Aggregate is applied on entire QuerySet and it generate result (summary) values over an entire QuerySet.

In Model:

class Books(models.Model):
    name = models.CharField(max_length=100)
    pages = models.IntegerField()
    price = models.DecimalField(max_digits=5, decimal_places=3)

In Shell:

>>> Books.objects.all().aggregate(Avg('price'))
# Above code will give the Average of the price Column 
>>> {'price__avg': 34.35}

Annotate
Annotate generate an independent summary for each object in a QuerySet.(We can say it iterate each object in a QuerySet and apply operation)

In Model:

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')

In View:

videos = Video.objects.values('id', 'name','video').annotate(Count('user_likes',distinct=True)

In view it will count the likes for each video

不交电费瞎发啥光 2024-12-20 10:20:37

这是主要的区别,但聚合的工作范围也比注释更大。注释本质上与查询集中的各个项目相关。如果您在多对多字段之类的字段上运行 Count 注释,您将为查询集的每个成员获得单独的计数(作为添加的属性)。但是,如果您要对聚合执行相同的操作,它将尝试对查询集的每个成员(甚至重复项)上的每个关系进行计数,并将其仅作为一个值返回。

That's the main difference, but aggregates also work on a grander scale than annotations. Annotations are inherently related to individual items in a queryset. If you run an Count annotation on a something like a many-to-many field, you'll get a separate count for each member of the queryset (as an added attribute). If you were to do the same with an aggregation, however, it would attempt to count every relationship on every member of the queryset, even duplicates, and return that as just one value.

会发光的星星闪亮亮i 2024-12-20 10:20:37
  • 聚合() 可以计算当前模型列的所有值。 *返回字典。

  • annotate() 可以计算通过外键访问子模型的列。 *返回一个QuerySet。

*Avg()Count(), Max()Min(), Sum() 等可以与 aggregate 一起使用()annotate()

例如,下面有 CategoryProduct 模型:

# "models.py"

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=20)

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)

并且,下面有 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 视图,其中包含idcategoryprice Avg() 中,Count(), Max(), Min()Sum() in 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('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}

{'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')}
{}

And、Max()Min下面的 () 可以接受非数字类型

# "views.py"

# ...

def test(request):

    print(Product.objects.aggregate(Count('name')))
    print(Product.objects.aggregate(Max('name')))
    print(Product.objects.aggregate(Min('name')))
        
    return HttpResponse("Test")

然后,下面这些字典将在控制台上输出:

{'name__count': 5}
{'name__max': 'Tea'}
{'name__min': 'Apple'}

But、Avg()Sum() 以下不能接受非数字类型

# "views.py"

# ...

def test(request):

    print(Product.objects.aggregate(Avg('name')))
    print(Product.objects.aggregate(Sum('name')))
        
    return HttpResponse("Test")

因此,会出现以下错误:

django.db.utils.ProgrammingError:函数 avg(字符变化)不存在

django.db.utils.ProgrammingError:函数 sum(字符变化)不存在

并且,您可以更改默认键名称,如下所示:

# "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():

现在,我运行 test 视图,其中包含product__idproduct__categoryproduct__price Avg()Count()Max()Min() 和 <代码>Sum() 中annotate() 如下所示。 *您需要将 __avg__count__max__min__sum 放入product__idproduct__categoryproduct__price 用于 Avg()Count()、<代码>最大(),分别是 Min()Sum()

# "views.py"

# ...

def test(request):

    qs = Category.objects.annotate(
        Avg('product__id'), 
        Count('product__id'), 
        Max('product__id'), 
        Min('product__id'), 
        Sum('product__id')
    ).order_by('pk')

    for obj in qs:
        print(
            obj.id, 
            obj.name, 
            obj.product__id__avg, 
            obj.product__id__count, 
            obj.product__id__max, 
            obj.product__id__min, 
            obj.product__id__sum
        )

    print()

    qs = Category.objects.annotate(
        Avg('product__category'), 
        Count('product__category'), 
        Max('product__category'), 
        Min('product__category'), 
        Sum('product__category')
    ).order_by('pk')

    for obj in qs:
        print(
            obj.id, 
            obj.name, 
            obj.product__category__avg, 
            obj.product__category__count, 
            obj.product__category__max, 
            obj.product__category__min, 
            obj.product__category__sum
        )

    print()

    qs = Category.objects.annotate(
        Avg('product__price'), 
        Count('product__price'), 
        Max('product__price'), 
        Min('product__price'), 
        Sum('product__price')
    ).order_by('pk')

    for obj in qs:
        print(
            obj.id, 
            obj.name, 
            obj.product__price__avg, 
            obj.product__price__count, 
            obj.product__price__max, 
            obj.product__price__min, 
            obj.product__price__sum
        )
    
    return HttpResponse("Test")

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

1 Food 2.0 3 3 1 6
2 Drink 4.5 2 5 4 9

1 Food 1.0 3 1 1 3
2 Drink 2.0 2 2 2 4

1 Food 20.0000000000000000 3 30.00 10.00 60.00
2 Drink 45.0000000000000000 2 50.00 40.00 90.00

并且,不带 order_by('pk') 下面使订单后代:

# "views.py"

# ...

def test(request):

    qs = Category.objects.annotate(
        Avg('product__price'), 
        Count('product__price'), 
        Max('product__price'), 
        Min('product__price'), 
        Sum('product__price')
    ) # Without ".order_by('pk')"

    for obj in qs:
        print(
            obj.id, 
            obj.name, 
            obj.product__price__avg, 
            obj.product__price__count, 
            obj.product__price__max, 
            obj.product__price__min, 
            obj.product__price__sum
        )
    
    return HttpResponse("Test")

然后,顺序是后代如下所示:

2 Drink 4.5 2 5 4 9
1 Food 2.0 3 3 1 6

并且,下面的annotate()idname属性:

# "views.py"

# ...

def test(request): 
                         # Empty "annotate()"
    qs = Category.objects.annotate().order_by('pk')

    for obj in qs:
        print(obj.id, obj.name)
        
    return HttpResponse("Test")

然后,下面这些控制台输出:

1 Food
2 Drink

但是,下面的annotate()没有__avg__count__max, __min和 __sum 属性如下所示:

# "views.py"

# ...

def test(request): 
                         # Empty "annotate()"
    qs = Category.objects.annotate().order_by('pk')
    
    for obj in qs:
        print(
            obj.product__price__avg,
            obj.product__price__count,
            obj.product__price__max,
            obj.product__price__min,
            obj.product__price__sum,
        )
        
    return HttpResponse("Test")

因此,出现以下错误:

属性错误:“类别”对象没有属性“product__price__avg”

属性错误:“类别”对象没有属性“product__price__count”

属性错误:“类别”对象没有属性“product__price__max”

属性错误:“类别”对象没有属性“product__price__min”

属性错误:“类别”对象没有属性“product__price__sum”

并且下面的 Max()Min() 可以接受非数字类型

# "views.py"

# ...

def test(request):

    qs = Category.objects.annotate(
        Count('product__name'), 
        Max('product__name'), 
        Min('product__name'), 
    ).order_by('pk')

    for obj in qs:
        print( 
            obj.product__name__count, 
            obj.product__name__max, 
            obj.product__name__min, 
        )

    return HttpResponse("Test")

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

3 Orange Apple
2 Tea Milk

但是,下面的 Avg()Sum() 不能接受非数字类型

# "views.py"

# ...

def test(request):

    qs = Category.objects.annotate(
        Avg('product__name'),
        Sum('product__name')
    ).order_by('pk')

    for obj in qs:
        print( 
            obj.product__name__avg, 
            obj.product__name__sum
        )
        
    return HttpResponse("Test")

因此,出现以下错误:

django.db.utils.ProgrammingError:函数 avg(字符变化)不存在

django.db.utils.ProgrammingError:函数 sum(字符变化)不存在

并且,您可以更改默认属性名称,如下所示:

# "views.py"

# ...

def test(request):

    qs = Category.objects.annotate(
        productPriceAvg=Avg('product__price'), 
        productPriceCount=Count('product__price'), 
        productPriceMax=Max('product__price'), 
        productPriceMin=Min('product__price'), 
        productPriceSum=Sum('product__price')
    ).order_by('pk')

    for obj in qs:
        print(
            obj.id, 
            obj.name, 
            obj.productPriceAvg, 
            obj.productPriceCount, 
            obj.productPriceMax, 
            obj.productPriceMin, 
            obj.productPriceSum
        )
    
    return HttpResponse("Test")

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

1 Food 20.0000000000000000 3 30.00 10.00 60.00
2 Drink 45.0000000000000000 2 50.00 40.00 90.00
  • aggregate() can calculates all values of the current model's column. *A dictionary is returned.

  • annotate() can calculates all values of the child model's column accessed by foreign key. *A QuerySet is returned.

*Avg(), Count(), Max(), Min(), Sum() and so on can be used with aggregate() and annotate().

For example, there are Category and Product models below:

# "models.py"

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=20)

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)

And, there are Category and Product admins below:

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

And, there are 2 categories below:

enter image description here

And, there are 5 products below:

enter image description here

And, there is test view below:

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

First, I explain about aggregate().

aggregate():

Now, I run test view which has the columns id, category and price in Avg(), Count(), Max(), Min() and Sum() in aggregate() as shown below:

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

Then, these dictionaries below are outputted on console:

{'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}

{'price__avg': Decimal('30.0000000000000000')}
{'price__count': 5}
{'price__max': Decimal('50.00')}
{'price__min': Decimal('10.00')}
{'price__sum': Decimal('150.00')}

And, aggregate() can accept multiple kinds of columns and functions in any order, the multiple same kind of columns and functions and no columns and functions as shown below. *The multiple same kind of columns and functions are made into one and no columns and functions get an empty dictionary:

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

Then, these dictionaries below are outputted on console:

{'price__max': Decimal('50.00'), 'category__max': 2, 'id__sum': 15, 'id__min': 1}
{'price__sum': Decimal('150.00')}
{}

And, Max() and Min() below can accept non-numeric types:

# "views.py"

# ...

def test(request):

    print(Product.objects.aggregate(Count('name')))
    print(Product.objects.aggregate(Max('name')))
    print(Product.objects.aggregate(Min('name')))
        
    return HttpResponse("Test")

Then, these dictionaries below are outputted on console:

{'name__count': 5}
{'name__max': 'Tea'}
{'name__min': 'Apple'}

But, Avg() and Sum() below cannot accept non-numeric types:

# "views.py"

# ...

def test(request):

    print(Product.objects.aggregate(Avg('name')))
    print(Product.objects.aggregate(Sum('name')))
        
    return HttpResponse("Test")

So, the errors below occur:

django.db.utils.ProgrammingError: function avg(character varying) does not exist

django.db.utils.ProgrammingError: function sum(character varying) does not exist

And, you can change the default key names as shown below:

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

Then, the default key names are changed as shown below:

{'priceAve': Decimal('30.0000000000000000')}
{'priceCount': 5}
{'priceMax': Decimal('50.00')}
{'priceMin': Decimal('10.00')}
{'priceSum': Decimal('150.00')}

Next, I explain about annotate().

annotate():

Now, I run test view which has the columns product__id, product__category and product__price in Avg(), Count(), Max(), Min() and Sum() in annotate() as shown below. *You need to put __avg, __count, __max, __min and __sum to product__id, product__category and product__price for Avg(), Count(), Max(), Min() and Sum() respectively:

# "views.py"

# ...

def test(request):

    qs = Category.objects.annotate(
        Avg('product__id'), 
        Count('product__id'), 
        Max('product__id'), 
        Min('product__id'), 
        Sum('product__id')
    ).order_by('pk')

    for obj in qs:
        print(
            obj.id, 
            obj.name, 
            obj.product__id__avg, 
            obj.product__id__count, 
            obj.product__id__max, 
            obj.product__id__min, 
            obj.product__id__sum
        )

    print()

    qs = Category.objects.annotate(
        Avg('product__category'), 
        Count('product__category'), 
        Max('product__category'), 
        Min('product__category'), 
        Sum('product__category')
    ).order_by('pk')

    for obj in qs:
        print(
            obj.id, 
            obj.name, 
            obj.product__category__avg, 
            obj.product__category__count, 
            obj.product__category__max, 
            obj.product__category__min, 
            obj.product__category__sum
        )

    print()

    qs = Category.objects.annotate(
        Avg('product__price'), 
        Count('product__price'), 
        Max('product__price'), 
        Min('product__price'), 
        Sum('product__price')
    ).order_by('pk')

    for obj in qs:
        print(
            obj.id, 
            obj.name, 
            obj.product__price__avg, 
            obj.product__price__count, 
            obj.product__price__max, 
            obj.product__price__min, 
            obj.product__price__sum
        )
    
    return HttpResponse("Test")

Then, these below are outputted on console:

1 Food 2.0 3 3 1 6
2 Drink 4.5 2 5 4 9

1 Food 1.0 3 1 1 3
2 Drink 2.0 2 2 2 4

1 Food 20.0000000000000000 3 30.00 10.00 60.00
2 Drink 45.0000000000000000 2 50.00 40.00 90.00

And, the query without order_by('pk') below makes the order descendant:

# "views.py"

# ...

def test(request):

    qs = Category.objects.annotate(
        Avg('product__price'), 
        Count('product__price'), 
        Max('product__price'), 
        Min('product__price'), 
        Sum('product__price')
    ) # Without ".order_by('pk')"

    for obj in qs:
        print(
            obj.id, 
            obj.name, 
            obj.product__price__avg, 
            obj.product__price__count, 
            obj.product__price__max, 
            obj.product__price__min, 
            obj.product__price__sum
        )
    
    return HttpResponse("Test")

Then, the order is descendant as shown below:

2 Drink 4.5 2 5 4 9
1 Food 2.0 3 3 1 6

And, empty annotate() below has id and name attributes:

# "views.py"

# ...

def test(request): 
                         # Empty "annotate()"
    qs = Category.objects.annotate().order_by('pk')

    for obj in qs:
        print(obj.id, obj.name)
        
    return HttpResponse("Test")

Then, these below are outputted on console:

1 Food
2 Drink

But, empty annotate() below doesn't have __avg, __count, __max, __min and __sum attributes as shown below:

# "views.py"

# ...

def test(request): 
                         # Empty "annotate()"
    qs = Category.objects.annotate().order_by('pk')
    
    for obj in qs:
        print(
            obj.product__price__avg,
            obj.product__price__count,
            obj.product__price__max,
            obj.product__price__min,
            obj.product__price__sum,
        )
        
    return HttpResponse("Test")

So, the errors below occur:

AttributeError: 'Category' object has no attribute 'product__price__avg'

AttributeError: 'Category' object has no attribute 'product__price__count'

AttributeError: 'Category' object has no attribute 'product__price__max'

AttributeError: 'Category' object has no attribute 'product__price__min'

AttributeError: 'Category' object has no attribute 'product__price__sum'

And, Max() and Min() below can accept non-numeric types:

# "views.py"

# ...

def test(request):

    qs = Category.objects.annotate(
        Count('product__name'), 
        Max('product__name'), 
        Min('product__name'), 
    ).order_by('pk')

    for obj in qs:
        print( 
            obj.product__name__count, 
            obj.product__name__max, 
            obj.product__name__min, 
        )

    return HttpResponse("Test")

Then, these below are outputted on console:

3 Orange Apple
2 Tea Milk

But, Avg() and Sum() below cannot accept non-numeric types:

# "views.py"

# ...

def test(request):

    qs = Category.objects.annotate(
        Avg('product__name'),
        Sum('product__name')
    ).order_by('pk')

    for obj in qs:
        print( 
            obj.product__name__avg, 
            obj.product__name__sum
        )
        
    return HttpResponse("Test")

So, the errors below occur:

django.db.utils.ProgrammingError: function avg(character varying) does not exist

django.db.utils.ProgrammingError: function sum(character varying) does not exist

And, you can change the default attribute names as shown below:

# "views.py"

# ...

def test(request):

    qs = Category.objects.annotate(
        productPriceAvg=Avg('product__price'), 
        productPriceCount=Count('product__price'), 
        productPriceMax=Max('product__price'), 
        productPriceMin=Min('product__price'), 
        productPriceSum=Sum('product__price')
    ).order_by('pk')

    for obj in qs:
        print(
            obj.id, 
            obj.name, 
            obj.productPriceAvg, 
            obj.productPriceCount, 
            obj.productPriceMax, 
            obj.productPriceMin, 
            obj.productPriceSum
        )
    
    return HttpResponse("Test")

Then, these below are outputted on console:

1 Food 20.0000000000000000 3 30.00 10.00 60.00
2 Drink 45.0000000000000000 2 50.00 40.00 90.00
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文