Django queryset使用日期时间计算进行注释

时间:2015-12-30 23:20:18

标签: django datetime django-queryset

我有一个带有两个日期时间的模型,一个用于创建日期,另一个用于完成日期。

class Task(models.Model):
...
created = models.DateTimeField(default=timezone.now)

STATUS = Choices(
    ('draft', 'Draft'),
    ('open', 'Open'),
    ('wip', 'In Progress'),
    ('completed', 'Completed'),
)

datetime_started = models.DateTimeField(blank=True, null=True)
datetime_wip = models.DateTimeField(blank=True, null=True)
datetime_completed = models.DateTimeField(blank=True, null=True)
...

我正在尝试注释一个查询集来计算完成Task所需的平均时间。我尝试使用Django的AvgF表达式,但无济于事:

today = timezone.now()
# We display the data of last 11 months + this month
tzinfo = timezone.get_current_timezone()
start_date = datetime(
    today.year,
    today.month,
    1,
    tzinfo=tzinfo) - relativedelta(months=11)

where = ("date_trunc('month', tasks_task.created AT TIME ZONE '%s')::date"
         % timezone.get_current_timezone_name())

tasks_last_12 = Task.objects.filter(
        created__range=(start_date, today),
    )
    .extra({'month': where})
    .values('month')
    .order_by('month')
    .annotate(
        cmpl_time=Avg(F('datetime_completed') - F('datetime_started')),
    )
    .values_list('month', 'cmpl_time')

...

TypeError: float() argument must be a string or a number, not 'datetime.timedelta'

然后,我尝试使用SumCount的组合来计算平均值,但这也不起作用:

tasks_last_12 = Task.objects.filter(
        created__range=(start_date, today),
    )
    .extra({'month': where})
    .values('month')
    .order_by('month')
    .annotate(
        cmpl_time=Sum(
            (F('datetime_completed') - F('datetime_started')) / Count('datetime_completed')

        )
    )
    .values_list('month', 'cmpl_time'))

...

FieldError: Expression contains mixed types. You must set output_field

我怎么能解决这个问题呢?

2 个答案:

答案 0 :(得分:1)

如果您使用的是Postgres,则可以使用django-pg-utils包。将持续时间字段转换为秒,然后取平均值

from pg_utils import Seconds
from django.db.models import Avg

Task.objects.annotate(cmpl_time=Avg(Seconds(F('datetime_completed') - F('datetime_started'))))

答案 1 :(得分:0)

迟到的回复,但是:

  1. 您可能需要在python中减去日期,而不是在ORM中:date1 - date2将为您提供timedelta个对象。求和,然后除以列表的len
  2. 尝试在Sum(..., output_field=DateField())
  3. 上为您的通话设置output_field参数
  4. cmpl_time的计算应在除Sum之前调用Count以计算平均值。