cleaner scales

- References to `Stat` in `Scale` objects are deleted (because scales
  are independent of stats)
- KFET_WAKES_UP_AT is now a time object insted of an hour
- Proper use of date, datetime, timedelta, etc (django.utils.timezone
  provides neither datetime nor timedelta)
This commit is contained in:
Aurélien Delobelle 2017-04-04 18:11:15 +02:00
parent 278459e80f
commit 885e40fd05

View file

@ -1,27 +1,29 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import ast import ast
from datetime import date, datetime, time, timedelta
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from django.utils import timezone from django.utils import timezone
from django.db.models import Sum from django.db.models import Sum
KFET_WAKES_UP_AT = 7 KFET_WAKES_UP_AT = time(7, 0)
def kfet_day(year, month, day, start_at=KFET_WAKES_UP_AT): def kfet_day(year, month, day, start_at=KFET_WAKES_UP_AT):
return timezone.datetime(year, month, day, hour=start_at) """datetime wrapper with time offset."""
return datetime.combine(date(year, month, day), start_at)
def to_kfet_day(dt, start_at=KFET_WAKES_UP_AT): def to_kfet_day(dt, start_at=KFET_WAKES_UP_AT):
kfet_dt = kfet_day(year=dt.year, month=dt.month, day=dt.day) kfet_dt = kfet_day(year=dt.year, month=dt.month, day=dt.day)
if dt.hour < start_at: if dt.time() < start_at:
kfet_dt -= timezone.timedelta(days=1) kfet_dt -= timedelta(days=1)
return kfet_dt return kfet_dt
class StatScale(object): class Scale(object):
name = None name = None
step = None step = None
@ -49,7 +51,7 @@ class StatScale(object):
@staticmethod @staticmethod
def by_name(name): def by_name(name):
for cls in StatScale.__subclasses__(): for cls in Scale.__subclasses__():
if cls.name == name: if cls.name == name:
return cls return cls
return None return None
@ -80,9 +82,9 @@ class StatScale(object):
return [begin.strftime(label_fmt) for begin, end in self] return [begin.strftime(label_fmt) for begin, end in self]
class DayStatScale(StatScale): class DayScale(Scale):
name = 'day' name = 'day'
step = timezone.timedelta(days=1) step = timedelta(days=1)
label_fmt = '%A' label_fmt = '%A'
@classmethod @classmethod
@ -90,19 +92,19 @@ class DayStatScale(StatScale):
return to_kfet_day(dt) return to_kfet_day(dt)
class WeekStatScale(StatScale): class WeekScale(Scale):
name = 'week' name = 'week'
step = timezone.timedelta(days=7) step = timedelta(days=7)
label_fmt = 'Semaine %W' label_fmt = 'Semaine %W'
@classmethod @classmethod
def get_chunk_start(cls, dt): def get_chunk_start(cls, dt):
dt_kfet = to_kfet_day(dt) dt_kfet = to_kfet_day(dt)
offset = timezone.timedelta(days=dt_kfet.weekday()) offset = timedelta(days=dt_kfet.weekday())
return dt_kfet - offset return dt_kfet - offset
class MonthStatScale(StatScale): class MonthScale(Scale):
name = 'month' name = 'month'
step = relativedelta(months=1) step = relativedelta(months=1)
label_fmt = '%B' label_fmt = '%B'
@ -132,9 +134,9 @@ def stat_manifest(scales_def=None, scale_args=None, **url_params):
def last_stats_manifest(scales_def=None, scale_args=None, **url_params): def last_stats_manifest(scales_def=None, scale_args=None, **url_params):
scales_def = [ scales_def = [
('Derniers mois', MonthStatScale, ), ('Derniers mois', MonthScale, ),
('Dernières semaines', WeekStatScale, ), ('Dernières semaines', WeekScale, ),
('Derniers jours', DayStatScale, ), ('Derniers jours', DayScale, ),
] ]
if scale_args is None: if scale_args is None:
scale_args = {} scale_args = {}
@ -160,7 +162,7 @@ class ScaleMixin(object):
scale_name = self.request.GET.get('scale', None) scale_name = self.request.GET.get('scale', None)
cls = StatScale.by_name(scale_name) cls = Scale.by_name(scale_name)
if cls is None: if cls is None:
scale = self.get_default_scale() scale = self.get_default_scale()
else: else:
@ -174,7 +176,7 @@ class ScaleMixin(object):
return context return context
def get_default_scale(self): def get_default_scale(self):
return DayStatScale(n_steps=7, last=True) return DayScale(n_steps=7, last=True)
def chunkify_qs(self, qs, scale, field=None): def chunkify_qs(self, qs, scale, field=None):
if field is None: if field is None: