每天平均支出-Django模型

时间:2019-03-05 17:13:32

标签: django django-models django-queryset

我有一个看起来像这样的模型:

class Payment(TimeStampModel):
    timestamp = models.DateTimeField(auto_now_add=True)
    amount = models.FloatField()
    creator = models.ForeignKey(to='Payer')

计算每天平均支出的正确方法是什么? 我可以按天汇总,但是付款者不花任何钱的日子就不算在内,这是不正确的

更新:

因此,假设我的数据库中只有两条记录,一条来自3月1日,一条来自1月1日。平均每天的花费应该是

(Sum of all spendings) / (March 1 - January 1) 

除以60

但是,这当然只会给我每件商品的平均支出,而天数会给我2:

for p in Payment.objects.all():
    print(p.timestamp, p.amount)
p = Payment.objects.all().dates('timestamp','day').aggregate(Sum('amount'), Avg('amount'))
print(p

输出:

2019-03-05 17:33:06.490560+00:00 456.0
2019-01-05 17:33:06.476395+00:00 123.0
{'amount__sum': 579.0, 'amount__avg': 289.5}

2 个答案:

答案 0 :(得分:1)

您可以汇总最小和最大时间戳以及金额的总和:

from django.db.models import Min, Max, Sum

def average_spending_per_day():
    aggregate = Payment.objects.aggregate(Min('timestamp'), Max('timestamp'), Sum('amount'))
    min_datetime = aggregate.get('timestamp__min')
    if min_datetime is not None:
        min_date = min_datetime.date()
        max_date = aggregate.get('timestamp__max').date()
        total_amount = aggregate.get('amount__sum')
        days = (max_date - min_date).days + 1
        return total_amount / days
    return 0

如果存在min_datetime,则db表中有一些数据,并且还有最大日期和总数,否则我们将返回0或任何您想要的值。

答案 1 :(得分:1)

这取决于您的后端,但是您想将金额之和除以最大时间戳和最小时间戳之间的天数差。在Postgres中,您可以简单地减去两个日期以获取它们之间的天数。在MySQL中,有一个名为DateDiff的函数,它接受两个日期并返回它们之间的天数。

class Date(Func):
    function = 'DATE'

class MySQLDateDiff(Func):
    function = 'DATEDIFF'

    def __init__(self, *expressions, **extra):
        expressions = [Date(exp) for exp in expressions]
        extra['output_field'] = extra.get('output_field', IntegerField())
        super().__init__(*expressions, **extra)

class PgDateDiff(Func):
    template = "%(expressions)s"
    arg_joiner = ' - '

    def __init__(self, *expressions, **extra):
        expressions = [Date(exp) for exp in expressions]
        extra['output_field'] = extra.get('output_field', IntegerField())
        super().__init__(*expressions, **extra)

agg = {
    avg_spend: ExpressionWrapper(
        Sum('amount') / (PgDateDiff(Max('timestamp'), Min('timestamp')) + Value(1)),
        output_field=DecimalField())
}
avg_spend = Payment.objects.aggregate(**agg)

这对我来说似乎是正确的,当然,我还没有测试过。当然,如果这是您的后端,请使用MySQLDateDiff。