Files
django-cresus/core/models.py
2017-09-24 11:42:05 +02:00

131 lines
4.4 KiB
Python

import datetime
from collections import defaultdict
from django.utils import timezone as tz
from django.db import models
# Create your models here.
class Etiquette(models.Model):
nom = models.CharField(max_length=128, unique=True)
def __str__(self):
return "%s" % self.nom
class MonthManager(models.Manager):
def get_queryset_for_month(self, month, year):
return super().get_queryset().filter(date__month=month,
date__year=year)
def get_queryset(self, month=None, year=None):
""" Add custom 'month' and 'year' keyword arguments, used as filters.
Without argument, simply proxy to parent method.
This method checks if month is newly created (first access). If
so, it spawns recursive records for this month.
"""
# Generic call
if not month and not year:
return super().get_queryset()
# Custom call
elif month and year:
recursifs = EnregistrementRecursif.objects.all()
if (not self.get_queryset_for_month(month, year).exists()
and recursifs.exists()):
print("LOG: Month is created so we populated it...")
for r in recursifs:
r.spawn(month, year)
return self.get_queryset_for_month(month, year)
# Invalid call
else:
raise TypeError(
"You must call with either none or \
both 'month' and 'year' keyword arguments")
def _populate_data(self, qs, data):
def somme_par_etiquette(qs):
sommes = defaultdict(lambda:0)
for el in qs:
sommes[el.etiquette.nom] += el.montant
return dict(sommes)
data['balance'] = sum(map(lambda t: t[0], qs.values_list('montant')))
data['par_etiquette'] = somme_par_etiquette(qs)
return data
def calculate_data(self, qs):
#TODO: cached results
return self._populate_data(qs, {})
def get_month_with_data(self, month, year):
""" Retrieve the queryset for given month and year, plus
some data calculated on the set """
qs = self.get_queryset(month=month, year=year)
data = self.calculate_data(qs)
return qs, data
class Enregistrement(models.Model):
objects = MonthManager()
date = models.DateField()
montant = models.FloatField()
etiquette = models.ForeignKey(Etiquette)
description = models.CharField(max_length=512)
def __str__(self):
return "<Depense: %s>" % self.etiquette
class Meta:
ordering = ('date',)
class EnregistrementRecursif(models.Model):
jour = models.IntegerField()
montant = models.FloatField()
etiquette = models.ForeignKey(Etiquette)
description = models.CharField(max_length=512)
created_date = models.DateField()
class Meta:
ordering = ('jour',)
def is_older(self, month, year):
return (self.created_date.month <= month
and self.created_date.year <= year)
def spawn(self, month, year, commit=True):
""" Spawn a new Enregistrement for given month and year. """
# Do not spawn for dates older than this instance creation date
if not self.is_older(month, year):
return None
# Create new Enregistrement from this instance values
date = datetime.date(year, month, self.jour)
new_object, created = Enregistrement.objects.get_or_create(date=date,
montant=self.montant,
etiquette=self.etiquette,
description=self.description)
if created and commit:
new_object.save()
return new_object
def save(self, **kwargs):
""" Update 'created_date' on each save, this avoids conflict with older
spawned instances.
"""
self.created_date = tz.now().date()
return super().save(**kwargs)
def __str__(self):
return "<[%i] %s (%s) : %s {%s}>" % (self.jour,
self.description,
self.etiquette,
self.montant,
self.created_date)