import pytz from functools import reduce # from collections import OrderedDict from datetime import datetime, time, timedelta from django.db.models import Max from celery import task from counter.models import DeviceCount from mosquito.models import MosqPostStatistic def max_count(x, y): if x.count > y.count: return x return y def shortest_date(date, date_list): distance_list = [(date - _date).days for _date in date_list] shortest_distance = min(filter(lambda x: x > 0, distance_list)) return shortest_distance @task() def update_daily_statistic(): # calc_ret = {} # queryset = DeviceCount.objects.raw( # 'select id, device_id, max(data_time) as max_date ' # 'from device_count group by device_id, date(data_time) order by max_date') # # if queryset: # ret = [] # for q in queryset: # entry = DeviceCount.objects.filter(device_id=q.device_id, data_time=q.max_date) # entry = reduce(max_count, entry) if len(entry) > 1 else entry[0] # ret.append((entry.data_time.date(), int(entry.count))) # if ret: # for item in ret: # key, value = item[0], item[1] # try: # calc_ret[key] += value # except KeyError: # calc_ret[key] = value queryset = DeviceCount.objects.raw('select id, date(data_time) as date from device_count group by date') if queryset: tz = pytz.timezone("UTC") ret = {} for q in queryset: midnight = tz.localize(datetime.combine(q.date, time(23, 59)), is_dst=None) daily_queryset = [DeviceCount.objects.filter(device_id=x['device_id'], data_time=x['max_time']) for x in DeviceCount.objects.filter(data_time__lte=midnight).values( 'device_id').annotate(max_time=Max('data_time'))] if daily_queryset: daily_queryset = [reduce(max_count, entry) if len(entry) > 1 else entry[0] for entry in daily_queryset] calc_result = sum(map(lambda x: int(x.count), daily_queryset)) date = q.date ret[date] = calc_result date_list = [k for k in ret] min_date = min(date_list) max_date = max(date_list) days = (max_date - min_date).days for d in range(1, days+1): date_ahead = min_date + timedelta(days=d) if date_ahead not in ret: distance = shortest_date(date_ahead, date_list) ret[date_ahead] = ret[date_ahead - timedelta(days=distance)] # Update statistic to MosqPostStatistic _date_list = [k for k in ret] _date_list.sort() is_first = True for d in _date_list: obj = MosqPostStatistic.objects.get(date=d) if is_first: if obj: obj.total, obj.increment = ret[d], ret[d] obj.save() else: MosqPostStatistic.objects.create(date=d, total=ret[d], increment=ret[d]) else: increment = ret[d] - ret[d-timedelta(days=1)] if obj: obj.total, obj.increment = ret[d], increment obj.save() else: MosqPostStatistic.objects.create(date=d, total=ret[d], increment=increment) is_first = False return _date_list @task() def update_latest_statistic(): pass