【问题标题】:average spending per day - django model每天的平均支出 - django 模型
【发布时间】:2019-03-05 17:13:32
【问题描述】:

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

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}

【问题讨论】:

  • 您可以添加示例数据以及您目前尝试的内容吗?
  • @ShafikurRahman 完成 - 在更新中添加了一些信息
  • 你使用什么数据库?我的第一个猜测是这只能使用原始 SQL,但是数据库类型是相关的。
  • 好吧,您可以只计算此期间所有付款的最小和最大日期之间的天数,然后将您的付款总额除以您的天数

标签: django django-models django-queryset


【解决方案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或任何你想要的。

【讨论】:

    【解决方案2】:

    这取决于您的后端,但您希望将金额的总和除以最大和最小时间戳之间的天数差。在 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。

    【讨论】:

      猜你喜欢
      • 2022-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多