Django/python 按月和季度聚合日期

2 投票
4 回答
5131 浏览
提问于 2025-04-16 11:00
ItemPrice.objects.filter(item__id = 1)
    .filter(date_lt = TODAY)
    .filter(date_gte = TODAY_MINUS_7_DAYS)
    .filter(date_.aggregate(Avg('value'))

我正在写一个功能,需要计算一个商品在不同时间段内的平均价格(比如一周、一个月、一个季度等)。这是我的模型:

class ItemPrice(models.Model):
    item = models.ForeignKey(Item)
    date = models.DateField()
    price = models.FloatField()

这个模型会记录商品随时间变化的价格,新商品会在频繁但不规律的时间点被添加进来。

计算过去一周的平均价格其实很简单,因为一周总是有7天。但是一个月和一个季度呢?它们的天数是不一样的……?

谢谢!

补充说明:这个应用是为一个金融机构开发的,30天的月份不太适用,感谢你的建议!

4 个回答

1

首先,你是想知道过去7天的情况,还是想了解上个星期的情况?如果你想要的是上个星期,那你的查询就不对了。

如果你关心的是过去的“n”天,那么你的查询就是正确的。我想你可以放轻松,直接用30天代表一个月,用90天代表一个季度就可以了。

2
import datetime
from dateutil import relativedelta, rrule  

obj = self.get_object()  
datenow = datetime.datetime.now() 

quarters = rrule.rrule(
        rrule.MONTHLY,
        bymonth=(1, 4, 7, 10),
        bysetpos=-1,
        dtstart=datetime.datetime(datenow.year, 1, 1),
        count=5)

    first_day = quarters.before(datenow)
    last_day = (quarters.after(datenow) - relativedelta.relativedelta(days=1))

    quarter = Payment.objects.filter(
        operation__department__cashbox__id=obj.pk,
        created__range=(first_day, last_day)).aggregate(count=Sum('amount'))

这里的内容是一个链接,指向StackOverflow网站上的一个问题解答。这个链接的标题是“从那里得到的灵感”。

2

这个解决方案分为两部分,第一部分是使用django ORM的聚合函数,第二部分是使用python-dateutil库。

from dateutil.relativedelta import relativedelta

A_MONTH = relativedelta(months=1)

month = ItemPrice.objects \
    .filter(date__gte = date - A_MONTH) \
    .filter(date__lt = date) \
    .aggregate(month_average = Avg('price'))

month的值是:

{'month_average': 40}

值得注意的是,你可以通过改变.aggregate()的参数来更改month字典的键。

dateutil中的relativedelta可以处理天、周、年等等,非常好用的库,我会重新编写我自己写的那些小工具。

撰写回答