Django 查询集注释与日期时间计算
Posted
技术标签:
【中文标题】Django 查询集注释与日期时间计算【英文标题】:Django queryset annotate with datetime calculations 【发布时间】:2016-04-04 23:22:15 【问题描述】:我的模型有两个日期时间,一个是实例创建日期,另一个是完成日期。
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 的 Avg
和 F
表达式,但无济于事:
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'
然后,我尝试使用Sum
和Count
的组合来计算平均值,但这也不起作用:
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
我该如何解决这个问题?
【问题讨论】:
【参考方案1】:回复晚了,但是:
-
您可能需要在 python 中减去日期,而不是在 ORM 中:
date1 - date2
将给您一个 timedelta
对象。将这些相加并除以列表中的len
。
尝试将 output_field 参数设置为您在 Sum(..., output_field=DateField())
上的调用
cmpl_time 的计算应在除以Count
之前调用Sum
以计算平均值。
【讨论】:
【参考方案2】:如果您使用的是 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'))))
【讨论】:
如果使用mysql呢?以上是关于Django 查询集注释与日期时间计算的主要内容,如果未能解决你的问题,请参考以下文章