我有一个表,其中包含一系列与时间段相关的条目(具体来说,是为客户工作的时间):
task_time: id | start_time | end_time | client (fk) 1 08/12/2011 14:48 08/12/2011 14:50 2
我试图从我的Django应用程序聚合给定客户端的所有工作时间:
time_worked_aggregate = models.TaskTime.objects.\ filter(client = some_client_id).\ extra(select = {'elapsed': 'SUM(task_time.end_time - task_time.start_time)'}).\ values('elapsed') if len(time_worked_aggregate) > 0: time_worked = time_worked_aggregate[0]['elapsed'].total_seconds() else: time_worked = 0
这似乎不优雅,但确实有效.或者至少我认为:事实证明它在PostgreSQL数据库上工作正常,但当我转移到SQLite时,一切都会消失.
一点挖掘表明,其原因是DateTime
s不是SQLite中的一流数据.以下原始SQLite查询将完成我的工作:
SELECT SUM(strftime('%s', end_time) - strftime('%s', start_time)) FROM task_time WHERE ...;
我的问题如下:
上面的Python示例似乎很迂回.我们能更优雅地做到这一点吗?
更重要的是,在这个阶段,我们能否以一种适用于Postgres和SQLite的方式实现?理想情况下,我不想编写原始SQL查询并切换恰好存在的数据库后端; 在一般的,Django是在保护我们从这个非常好.Django对此操作有合理的抽象吗?如果没有,对我来说在后端进行条件切换有什么明智的方法?
我应该提一下,数据集是数千个条目; 以下不太实际:
sum([task_time.end_date - task_time.start_date for task_time in models.TaskTime.objects.filter(...)])
小智.. 10
几乎与@andri提出的解决方案相同.在最终结果中,您将获得相同的数据. ExpressionWrapper - Django 1.8中的新功能.
from datetime import timedelta from django.db.models import ExpressionWrapper, F, fields from app.models import MyModel duration = ExpressionWrapper(F('closed_at') - F('opened_at'), output_field=fields.DurationField()) objects = MyModel.objects.closed().annotate(duration=duration).filter(duration__gt=timedelta(seconds=2)) for obj in objects: print obj.id, obj.duration, obj.duration.seconds # sample output # 807 0:00:57.114017 57 # 800 0:01:23.879478 83 # 804 3:40:06.797188 13206 # 801 0:02:06.786300 126
andilabs.. 5
我认为自Django 1.8以来,我们可以做得更好:
我只想绘制带有注释的部分,而带有聚合的其他部分应该很简单:
from django.db.models import F, Func SomeModel.objects.annotate( duration = Func(F('end_date'), F('start_date'), function='age') )
[有关postgres年龄函数的更多信息,请参见:http : //www.postgresql.org/docs/8.4/static/functions-datetime.html ]
SomeModel的每个实例都将使用duration
包含时差的字段进行注释,该时差在python中将是一个datetime.timedelta()
对象[有关datetime timedelta的更多信息,请点击此处:https ://docs.python.org/2/library/datetime.html#timedelta-objects ]
几乎与@andri提出的解决方案相同.在最终结果中,您将获得相同的数据. ExpressionWrapper - Django 1.8中的新功能.
from datetime import timedelta from django.db.models import ExpressionWrapper, F, fields from app.models import MyModel duration = ExpressionWrapper(F('closed_at') - F('opened_at'), output_field=fields.DurationField()) objects = MyModel.objects.closed().annotate(duration=duration).filter(duration__gt=timedelta(seconds=2)) for obj in objects: print obj.id, obj.duration, obj.duration.seconds # sample output # 807 0:00:57.114017 57 # 800 0:01:23.879478 83 # 804 3:40:06.797188 13206 # 801 0:02:06.786300 126
我认为自Django 1.8以来,我们可以做得更好:
我只想绘制带有注释的部分,而带有聚合的其他部分应该很简单:
from django.db.models import F, Func SomeModel.objects.annotate( duration = Func(F('end_date'), F('start_date'), function='age') )
[有关postgres年龄函数的更多信息,请参见:http : //www.postgresql.org/docs/8.4/static/functions-datetime.html ]
SomeModel的每个实例都将使用duration
包含时差的字段进行注释,该时差在python中将是一个datetime.timedelta()
对象[有关datetime timedelta的更多信息,请点击此处:https ://docs.python.org/2/library/datetime.html#timedelta-objects ]