"""Ensemble des classes d'utilité publique :-)""" from django.db import models from datetime import datetime, date, time, timedelta from django.utils import timezone import markdown def get_number_of_weeks_between(start, stop): """ Renvoie le nombre de semaines entre deux dates. Par extension, cela permet de connaitre le nombre d'occurence d'un évènement (entraînement, par exemple) hebdromadaire entre deux dates et ainsi pouvoir plannifier. :param start: date de début de la période :type start: datetime.date :param stop: date de fin de la période :type stop: datetime.date :return: Le nombre de semaines entre les deux dates. Remarks: Proposition d'utiliser isocalendar() sur une date. L'indice 1 de la valeur de retour donne la semaine correspondant. Eg. >>> from datetime import date >>> d = date(2020, 9, 27) >>> d.isocalendar() (2020, 39, 7) -> Est-ce qu'il ne suffirait pas de faire la différence ? """ tmp = stop - start number_of_days = abs(tmp.days) number_of_week = int((number_of_days + 1) / 7) if ((number_of_days + 1) % 7) > 0: number_of_week += 1 if tmp.days < 0: number_of_week *= -1 return number_of_week class TemporizableQuerySet(models.QuerySet): """ Classe permettant de spécifier le `QuerySet` de la classe `Temporizable`. """ def next(self, limit): """ Renvoie la liste des prochains "temporizable" (par rapport à la date du jour). :param limit: nombre d'éléments désirés. :type limit: int :return: une liste de `limit` éléments temporizables. """ return self.filter(datebegin__gte=timezone.now()).order_by("datebegin")[0:limit] def last(self, limit): """ Renvoie la liste des derniers "temporizable" (par rapport à la date du jour). :param limit: nombre d'éléments désirés. :type limit: int :return: une liste de `limit` éléments temporizables """ return self.filter(dateend__lte=timezone.now()).order_by("-dateend")[0:limit] # def get(self, date_string): # """ # """ # try: # selected_object = self.get(datebegin__lte=date_string, dateend__gte=date_string) # except self.DoesNotExist: # return None # except self.MultipleObjectsReturned: # return None # return selected_object class Temporizable(models.Model): """ Classe abstraite définissant une période comprise entre deux dates. """ class Meta: abstract = True datebegin = models.DateTimeField(verbose_name="Début") dateend = models.DateTimeField(blank=True, verbose_name="Fin") objects = models.Manager.from_queryset(TemporizableQuerySet)() def get_total_occurence(self): """ Renvoie le nombre de semaines entre les deux dates d'une instance de la classe `Temporizable`. :return: nombre de semaines. """ return get_number_of_weeks_between(self.datebegin.date(), self.dateend.date()) def get_number_of_occurence_to_event(self, the_date): """ Renvoie le nombre semaines entre une date choisie et le début (datebegin) d'une instance de la classe `Temporizable`. :param the_date: date par rapport à laquelle le calcul sera fait. :type the_date: datetime.date :return: nombre de semaines. """ return get_number_of_weeks_between(the_date, self.datebegin.date()) def get_number_of_occurence_inbetween(self, the_date, rest=True): """ Renvoie le nombre semaines entre une date choisie et une instance de la classe `Temporizable`. Le calcul peut se faire soit entre la date choisie et le date de fin d'une occurence de la classe, soit entre la date de début d'une occurence de la classe et la date choisie. :param the_date: date par rapport à laquelle le calcul sera fait. :type the_date: datetime.date :param rest: paramètre définissant s'il faut calculer le reste des occurences à venir (depuis `the_date` jusqu'à la date de fin) ou les occurences déjà passées (depuis la date de début jusqu'à `the_date`) :type rest: booléen :return: nombre de semaines. """ if rest: return get_number_of_weeks_between(the_date, self.dateend.date()) else: return get_number_of_weeks_between(self.datebegin.date(), the_date) class Markdownizable(models.Model): """ Classe abstraite ajoutant un champ `informations`, convertible de .md -> .html. """ class Meta: abstract = True informations = models.TextField( null=True, blank=True, verbose_name="Comments", help_text="Only MarkDown is authorized", ) def to_markdown(self): """Convertit le champ `informations` en (Github-flavored) Markdown.""" return markdown.markdown(self.informations)