带有聚合的Django子查询

时间:2019-04-30 16:45:12

标签: django

我有两个名为UserTransaction的模型。在这里,我想获得状态为成功的所有用户的交易金额总和。

我尝试了子查询,但是我没有得到如何用条件注释子查询的集合

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)

4 个答案:

答案 0 :(得分:0)

要使用子查询,请使用以下命令:

query=User.objects.annotate(total_spent=Subquery(subquery.values("user")[:1])).order_by("total_spent")

答案 1 :(得分:0)

您可以点击以下查询:

from django.db.models import Avg, Count, Min, Sum

User.objects.filter(status="success").annotate(total_amount=Sum('transaction__amount'))

答案 2 :(得分:0)

通过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导致选择所需的一个值。

答案 3 :(得分:0)

当模型上有排序设置时,建议的解决方案对我不起作用。

    subquery.query.clear_ordering(True)

我需要清除顺序以使其再次工作。

def with_installment_reservations_amounts(self):
    """
    Sum of initial amount of active installment reservations annotated in _installment_reservations_initial_amount
    Sum of principal amount of active installment reservations annotated in _installment_reservations_amount
    `.values('customer')` in subquery is used to properly sum values. See https://stackoverflow.com/questions/55925437/django-subquery-with-aggregate for more details.
    also this does not work when there is an ordering set on a model for some reason, so we need to clear it.
    """

    reservation_query = InstallmentReservation.objects.filter(customer_id=OuterRef('pk')).active().values('customer')
    reservation_query.query.clear_ordering(True)

    return self.annotate(
        _installment_reservations_amount=Coalesce(Subquery(reservation_query.annotate(sum=Sum('amount_principal')).values('sum')[:1]), Decimal(0),),
        _installment_reservations_initial_amount=Coalesce(Subquery(reservation_query.annotate(sum=Sum('initial_installment_amount')).values('sum')[:1]), Decimal(0),),
    )

整个代码示例 - 查询集上的一个方法 - 希望对您有所帮助

sum(request_total)