首页 > 解决方案 > 带有聚合的 Django 子查询

问题描述

我有两个模型叫做Userand Transaction。在这里,我想获取状态为成功的交易金额总和的所有用户。

我已经尝试过使用子查询,但我没有得到如何用条件注释子查询的聚合

class User(models.Model):
  name = models.CharField(max_length=128)

class Transaction(models.Model):
  user = models.ForeignKey(User)
  status = models.CharField(choices=(("success", "Success"),("failed", "Failed")))
   amount = models.DecimalField(max_digits=10, decimal_places=2)

subquery = Transaction.objects.filter(status="success", user=OuterRef('pk')).aggregate(total_spent = Coalesce(Sum('amount'), 0))

query = User.objects.annotate(total_spent=Subquery(subquery:how to do here ?)).order_by(how to order here by total_spent)

标签: django

解决方案


使用django-sql-utils包使这变得容易得多。

from django.db.models import Sum,
from sql_util.utils import SubqueryAggregate

User.objects.annotate(
    total_spend=SubqueryAggregate('transaction__amount',
                                  filter=Q(status='success'),
                                  aggregate=Sum)
)

如果你想长期这样做(没有 django-sql-utils),你需要知道关于子查询的这两件事:

  1. 使用前无法评估

  2. 它只能返回具有单个列的单个记录

因此,您不能调用aggregate子查询,因为这会立即评估子查询。相反,您必须注释该值。您还必须按外部 ref 值进行分组,否则您只需独立注释每个 Transaction。

subquery = Transaction.objects.filter(
        status='success', user=OuterRef('pk')
    ).values(
        'user__pk'
    ).annotate(
        total_spend=Sum('amount')
    ).values(
        'total_spend'
    )

第一个.values导致正确的分组依据。第二个.values原因是选择您想要的一个值。


推荐阅读