Django QuerySet APIでTimeFieldの合計を求める
TimeFieldとSum
Django QuerySet APIでTimeFieldの合計を普通にSumを使って求めようとすると…
# sample.py
from django.db.models import Sum
Book.objects.annotate(sec=Sum('time'))
01:00:00, 00:30:00, 00:40:00の合計が17000とおかしな値で帰ってきてしまいます。
TIME_TO_SEC関数
どうもこれは、MySQLのバグらしいのですが、
関数を噛ましてあげると回避できるようです。TIME_TO_SEC
なので、DjangoでTIME_TO_SEC
関数が使えるように設定してあげると治ります。
# sample.py
from django.db.models import Sum, Func
class Time_to_sec(Func):
function = 'TIME_TO_SEC'
lookup_name = 'sec'
Book.objects.annotate(sec=Sum(Time_to_sec('time')))
01:00:00, 00:30:00, 00:40:00の合計は7800となり、合計秒数が取得できます。
SEC_TO_TIME関数
MySQLでは
関数でSECからTIMEに戻すことができるのですが…SEC_TO_TIME
# sample.py
from django.db.models import Func
class Sec_to_time(Func):
function = 'SEC_TO_TIME'
lookup_name = 'time'
Pythonの仕様上、Timeオブジェクトは23:59:59.999999以内の時間しか定義することができないので、24時間を超えてしまうとエラーとなってしまいます。
なので、Python側で合計秒数を時間の差を示すtimedeltaオブジェクトに変換して使います。
# sample.py
import datetime
str(datetime.timedelta(seconds=666)) # '0:11:06'