簡體   English   中英

Django.aggregate() on.annotate()

[英]Django .aggregate() on .annotate()

是否可以聚合查詢集的注釋?

楷模:

class Article(models.Model):
    title = models.CharField(max_length=255)
    body = models.TextField()

class State(models.Model):
    article = Models.ForeignKey(Article)
    date = DateField()
    views = IntegerField()
    downloads = IntegerField()

我正在嘗試執行以下操作:

articles = metrics_models.Article.objects.filter(
    state__date__month=month,
    state__date__year=year
).annotate(
    views=Min('state__views'),
    downloads=Min('state__downloads')
).aggregate(
    views=Sum('views'),
    downloads=Sum('downloads')
)

錯誤:

Exception Type: DatabaseError
Exception Value:    
column "downloads" does not exist
LINE 1: SELECT SUM(downloads), SUM(views) FROM (SELECT "metrics_arti...

運行此程序時,我收到 DatabaseError,因為 django 嘗試對“視圖”和“下載”數據庫列進行聚合,而不是對注釋進行聚合。

有沒有其他方法可以在 QuerySet 注釋上進行這種聚合?

我認為medmunds是對的,你不能重復使用相同的名稱來注釋和聚合別名。 我想你想做什么:

articles = metrics_models.Article.objects.filter(
    state__date__month=month,
    state__date__year=year
).annotate(
    min_views=Min('state__views'),
    min_downloads=Min('state__downloads')
).aggregate(
    sum_min_views=Sum('min_views'),
    sum_min_downloads=Sum('min_downloads')
)

根據您的原始查詢,我認為這會起作用。

from django.db.models import ExpressionWrapper, Min, OuterRef

articles = (
    Article.objects.filter(state__date__month=month, state__date__year=year)
    .annotate(
        views=ExpressionWrapper(
            Min(
                State.objects.filter(article_id=OuterRef("id")).values_list(
                    "views", flat=True
                )
            ),
            output_field=models.IntegerField(),
        ),
        downloads=ExpressionWrapper(
            Min(
                State.objects.filter(article_id=OuterRef("id")).values_list(
                    "downloads", flat=True
                )
            ),
            output_field=models.IntegerField(),
        ),
    )
    .aggregate(views=Sum("views"), downloads=Sum("downloads"))
)

當您對 annotate() 方法和 aggregate() 方法使用相同的字段名稱時,您將在查詢集中的每個 object 上創建一個具有該名稱的新字段,然后嘗試獲取該字段的總和。

但是,由 annotate() 方法創建的新字段與傳遞給 aggregate() 方法的字段不同。

annotate()方法在queryset中的每一個object上創建一個新字段,包含計算的結果,這個字段不存儲在數據庫中,它只存在於memory中的queryset中。

另一方面,傳遞給 aggregate() 方法的字段是對存儲在數據庫/查詢集中的字段的引用,它用於獲取存儲在數據庫中的值的總和。

因此,當您對 annotate() 和 aggregate() 方法使用相同的字段名稱時,您試圖對僅存在於 memory 中的字段的值求和(您在聚合方法上聲明的那個會覆蓋來自 annotate 的那個) ,不在數據庫/查詢集中。 這就是您沒有獲得預期結果的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM