Django ORM 中的自定义 TruncFunc

Custom TruncFunc in Django ORM

我有一个具有以下结构的 Django 模型:

class BBPerformance(models.Model):
    marketcap_change = models.FloatField(verbose_name="marketcap change", null=True, blank=True)
    bb_change = models.FloatField(verbose_name="bestbuy change", null=True, blank=True)
    created_at = models.DateTimeField(verbose_name="created at", auto_now_add=True)
    updated_at = models.DateTimeField(verbose_name="updated at", auto_now=True)

我希望每 3 天对对象有一个 Avg 聚合函数。
例如,我编写了一个查询集,每天或使用类似 TruncDay 函数的方法进行此聚合。

queryset = BBPerformance.objects.annotate(day=TruncDay('created_at')).values('day').annotate(marketcap_avg=Avg('marketcap_change'),bb_avg=Avg('bb_change')

我怎样才能得到一个包含 3 天间隔的聚合值和该间隔第二天的索引的查询集?

我想这在数据库级别是不可能的(并且 Trunc 是数据库级别的函数),因为 Postgres and Oracle.

只支持月、日、周等。

所以我建议使用 TruncDay,然后添加 python 代码以按 3 天对它们进行分组。

下面的应该可以工作,虽然它有点难看。

如果您得到每一行的日期和最小日期之间的天数差异,您可以利用此差异的 Mod 计算出您需要移动多少天才能获得“中间”日期。然后可以使用值查询对这个中间日期进行分组

import datetime
from django.db.models import F, IntegerField, Avg, Min, DurationField, DateField
from django.db.models.functions import Cast, Mod, Extract

BBPerformance.objects.order_by(
    'created_at'
).annotate(
    diff=F('created_at__date') - BBPerformance.objects.aggregate(min=Min('created_at__date'))['min']
).annotate(
    diff_days=Cast(Extract('diff', 'days'), output_field=IntegerField())
).annotate(
    to_shift=Mod('diff_days', 3) - 1
).annotate(
    grouped_date=Cast(F('created_at__date') - Cast(F('to_shift') * datetime.timedelta(days=1), output_field=DurationField()), output_field=DateField())
).order_by(
    'grouped_date'
).values(
    'grouped_date'
).annotate(
    marketcap_avg=Avg('marketcap_change'),
    bb_avg=Avg('bb_change')
)