|
|
|
@ -13,496 +13,500 @@ from people.models import Gymnast
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_week(a_date):
|
|
|
|
|
"""
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
Remarks:
|
|
|
|
|
Je ne comprends pas trop cette fonction...
|
|
|
|
|
Tu pars d'une date, et tu récupères le lundi et le samedi de la semaine correspondant ?
|
|
|
|
|
"""
|
|
|
|
|
the_date = pendulum.parse(a_date)
|
|
|
|
|
day = the_date.weekday()
|
|
|
|
|
monday = the_date - timedelta(days=day)
|
|
|
|
|
sunday = the_date + timedelta(days=(6 - day))
|
|
|
|
|
return monday, sunday
|
|
|
|
|
Remarks:
|
|
|
|
|
Je ne comprends pas trop cette fonction...
|
|
|
|
|
Tu pars d'une date, et tu récupères le lundi et le samedi de la semaine correspondant ?
|
|
|
|
|
"""
|
|
|
|
|
the_date = pendulum.parse(a_date)
|
|
|
|
|
day = the_date.weekday()
|
|
|
|
|
monday = the_date - timedelta(days=day)
|
|
|
|
|
sunday = the_date + timedelta(days=(6 - day))
|
|
|
|
|
return monday, sunday
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
"""
|
|
|
|
|
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.
|
|
|
|
|
: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.
|
|
|
|
|
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)
|
|
|
|
|
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 ?
|
|
|
|
|
"""
|
|
|
|
|
-> 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)
|
|
|
|
|
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 ((number_of_days + 1) % 7) > 0:
|
|
|
|
|
number_of_week += 1
|
|
|
|
|
|
|
|
|
|
if tmp.days < 0:
|
|
|
|
|
number_of_week *= -1
|
|
|
|
|
if tmp.days < 0:
|
|
|
|
|
number_of_week *= -1
|
|
|
|
|
|
|
|
|
|
return number_of_week
|
|
|
|
|
return number_of_week
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TemporizableQuerySet(models.QuerySet):
|
|
|
|
|
"""
|
|
|
|
|
Classe permettant de spécifier le `QuerySet` de la classe `Temporizable`.
|
|
|
|
|
"""
|
|
|
|
|
"""
|
|
|
|
|
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).
|
|
|
|
|
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]
|
|
|
|
|
: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).
|
|
|
|
|
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]
|
|
|
|
|
: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
|
|
|
|
|
# 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
|
|
|
|
|
# return selected_object
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Temporizable(models.Model):
|
|
|
|
|
"""Classe abstraite définissant une période comprise entre deux dates.
|
|
|
|
|
"""Classe abstraite définissant une période comprise entre deux dates.
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
abstract = True
|
|
|
|
|
class Meta:
|
|
|
|
|
abstract = True
|
|
|
|
|
|
|
|
|
|
datebegin = models.DateTimeField(verbose_name="Début")
|
|
|
|
|
dateend = models.DateTimeField(blank=True, verbose_name="Fin")
|
|
|
|
|
datebegin = models.DateTimeField(verbose_name="Début")
|
|
|
|
|
dateend = models.DateTimeField(blank=True, verbose_name="Fin")
|
|
|
|
|
|
|
|
|
|
objects = models.Manager.from_queryset(TemporizableQuerySet)()
|
|
|
|
|
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`.
|
|
|
|
|
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())
|
|
|
|
|
: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`.
|
|
|
|
|
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())
|
|
|
|
|
: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.
|
|
|
|
|
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)
|
|
|
|
|
: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 Season(Temporizable):
|
|
|
|
|
"""
|
|
|
|
|
Classe représentant une saison. Une saison est déinie par :
|
|
|
|
|
- un id,
|
|
|
|
|
- un label,
|
|
|
|
|
- une date de début et
|
|
|
|
|
- une date de fin.
|
|
|
|
|
"""
|
|
|
|
|
Classe représentant une saison. Une saison est déinie par :
|
|
|
|
|
- un id,
|
|
|
|
|
- un label,
|
|
|
|
|
- une date de début et
|
|
|
|
|
- une date de fin.
|
|
|
|
|
|
|
|
|
|
La date de début est très souvent le : 01/09/xxxx
|
|
|
|
|
La date de fin est très souvent le : 31/08/xxxy
|
|
|
|
|
exemple : 1/9/2015 - 31/8/2016
|
|
|
|
|
"""
|
|
|
|
|
La date de début est très souvent le : 01/09/xxxx
|
|
|
|
|
La date de fin est très souvent le : 31/08/xxxy
|
|
|
|
|
exemple : 1/9/2015 - 31/8/2016
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Season"
|
|
|
|
|
verbose_name_plural = "Seasons"
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Season"
|
|
|
|
|
verbose_name_plural = "Seasons"
|
|
|
|
|
|
|
|
|
|
label = models.CharField(max_length=11, verbose_name="Label")
|
|
|
|
|
# active ou default = models.BooleanField(verbose_name='Défaut')
|
|
|
|
|
label = models.CharField(max_length=11, verbose_name="Label")
|
|
|
|
|
# active ou default = models.BooleanField(verbose_name='Défaut')
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s" % (self.label)
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s" % (self.label)
|
|
|
|
|
|
|
|
|
|
def week_number_from_begin(self, target_date):
|
|
|
|
|
return get_number_of_weeks_between(self.datebegin.date(), target_date)
|
|
|
|
|
def week_number_from_begin(self, target_date):
|
|
|
|
|
return get_number_of_weeks_between(self.datebegin.date(), target_date)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EventType(models.Model):
|
|
|
|
|
"""
|
|
|
|
|
Classe représentant les types d'évènements.
|
|
|
|
|
C'est un dictionnaire fini :
|
|
|
|
|
- compétiton qualificative,
|
|
|
|
|
- compétition finale,
|
|
|
|
|
- démonstration,
|
|
|
|
|
- …
|
|
|
|
|
"""
|
|
|
|
|
"""
|
|
|
|
|
Classe représentant les types d'évènements.
|
|
|
|
|
C'est un dictionnaire fini :
|
|
|
|
|
- compétiton qualificative,
|
|
|
|
|
- compétition finale,
|
|
|
|
|
- démonstration,
|
|
|
|
|
- …
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Event Type"
|
|
|
|
|
verbose_name_plural = "Event Types"
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Event Type"
|
|
|
|
|
verbose_name_plural = "Event Types"
|
|
|
|
|
|
|
|
|
|
name = models.CharField(max_length=255, verbose_name="Nom")
|
|
|
|
|
acronym = models.CharField(max_length=5, verbose_name="Acronyme")
|
|
|
|
|
name = models.CharField(max_length=255, verbose_name="Nom")
|
|
|
|
|
acronym = models.CharField(max_length=5, verbose_name="Acronyme")
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s (%s)" % (self.name, self.acronym)
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s (%s)" % (self.name, self.acronym)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Event(Markdownizable, Temporizable):
|
|
|
|
|
"""Classe représentant les évènements.
|
|
|
|
|
"""Classe représentant les évènements.
|
|
|
|
|
|
|
|
|
|
Un évènement est caractérisé par :
|
|
|
|
|
* un nom,
|
|
|
|
|
* un lieu (place),
|
|
|
|
|
* un type (compétition, démonstration, …),
|
|
|
|
|
* des gymnastes (participation prévue).
|
|
|
|
|
Je ne me rapelle plus à quoi sert le club.
|
|
|
|
|
"""
|
|
|
|
|
Un évènement est caractérisé par :
|
|
|
|
|
* un nom,
|
|
|
|
|
* un lieu (place),
|
|
|
|
|
* un type (compétition, démonstration, …),
|
|
|
|
|
* des gymnastes (participation prévue).
|
|
|
|
|
Je ne me rapelle plus à quoi sert le club.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Event"
|
|
|
|
|
verbose_name_plural = "Event"
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Event"
|
|
|
|
|
verbose_name_plural = "Event"
|
|
|
|
|
|
|
|
|
|
place = models.ForeignKey(
|
|
|
|
|
"location.Place", verbose_name="Lieu", on_delete=models.CASCADE, default=None
|
|
|
|
|
)
|
|
|
|
|
eventtype = models.ForeignKey(
|
|
|
|
|
EventType, verbose_name="Type", on_delete=models.CASCADE, default=None
|
|
|
|
|
)
|
|
|
|
|
name = models.CharField(max_length=255, verbose_name="Nom")
|
|
|
|
|
# club = models.ManyToManyField('location.Club', related_name="concernate_by", blank=True)
|
|
|
|
|
gymnasts = models.ManyToManyField(
|
|
|
|
|
"people.Gymnast",
|
|
|
|
|
through="Event_Participation",
|
|
|
|
|
related_name="participate_to",
|
|
|
|
|
verbose_name="Participants",
|
|
|
|
|
)
|
|
|
|
|
place = models.ForeignKey(
|
|
|
|
|
"location.Place", verbose_name="Lieu", on_delete=models.CASCADE, default=None
|
|
|
|
|
)
|
|
|
|
|
eventtype = models.ForeignKey(
|
|
|
|
|
EventType, verbose_name="Type", on_delete=models.CASCADE, default=None
|
|
|
|
|
)
|
|
|
|
|
name = models.CharField(max_length=255, verbose_name="Nom")
|
|
|
|
|
# club = models.ManyToManyField('location.Club', related_name="concernate_by", blank=True)
|
|
|
|
|
gymnasts = models.ManyToManyField(
|
|
|
|
|
"people.Gymnast",
|
|
|
|
|
through="Event_Participation",
|
|
|
|
|
related_name="participate_to",
|
|
|
|
|
verbose_name="Participants",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s (à %s)" % (self.name, self.place.city)
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s (à %s)" % (self.name, self.place.city)
|
|
|
|
|
|
|
|
|
|
def save(self, *args, **kwargs):
|
|
|
|
|
self.checkdates()
|
|
|
|
|
super().save(*args, **kwargs)
|
|
|
|
|
def save(self, *args, **kwargs):
|
|
|
|
|
self.checkdates()
|
|
|
|
|
super().save(*args, **kwargs)
|
|
|
|
|
|
|
|
|
|
def checkdates(self):
|
|
|
|
|
"""
|
|
|
|
|
Fonction assignant la date de fin d'un évènement à la date de début, si la date
|
|
|
|
|
de fin n'est pas définie, l'heure de fin est par défaut 18h00.
|
|
|
|
|
"""
|
|
|
|
|
if self.dateend is None and self.datebegin is not None:
|
|
|
|
|
self.dateend = datetime.combine(self.datebegin.date(), time(18, 0))
|
|
|
|
|
def checkdates(self):
|
|
|
|
|
"""
|
|
|
|
|
Fonction assignant la date de fin d'un évènement à la date de début, si la date
|
|
|
|
|
de fin n'est pas définie, l'heure de fin est par défaut 18h00.
|
|
|
|
|
"""
|
|
|
|
|
if self.dateend is None and self.datebegin is not None:
|
|
|
|
|
self.dateend = datetime.combine(self.datebegin.date(), time(18, 0))
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def number_of_week_from_today(self):
|
|
|
|
|
today = pendulum.now().date()
|
|
|
|
|
return get_number_of_weeks_between(today, self.datebegin.date())
|
|
|
|
|
@property
|
|
|
|
|
def number_of_week_from_today(self):
|
|
|
|
|
today = pendulum.now().date()
|
|
|
|
|
return get_number_of_weeks_between(today, self.datebegin.date())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Event_Participation(models.Model):
|
|
|
|
|
"""
|
|
|
|
|
"""
|
|
|
|
|
"""
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
event = models.ForeignKey(Event, on_delete=models.CASCADE)
|
|
|
|
|
gymnast = models.ForeignKey("people.Gymnast", on_delete=models.CASCADE)
|
|
|
|
|
rank = models.PositiveSmallIntegerField(default=0)
|
|
|
|
|
event = models.ForeignKey(Event, on_delete=models.CASCADE)
|
|
|
|
|
gymnast = models.ForeignKey("people.Gymnast", on_delete=models.CASCADE)
|
|
|
|
|
rank = models.PositiveSmallIntegerField(default=0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Course(Markdownizable, Temporizable):
|
|
|
|
|
"""Classe représentant les cours.
|
|
|
|
|
"""Classe représentant les cours.
|
|
|
|
|
|
|
|
|
|
Un cours est défini par :
|
|
|
|
|
* une heure de début et une heure de fin,
|
|
|
|
|
* une date de début et une date de fin (un cours est considéré comme donné hebdromadairement entre
|
|
|
|
|
ces deux dates) (hérite de la classe `Temporizable`)
|
|
|
|
|
* est associé à un ou plusieurs entraineurs,
|
|
|
|
|
* est associé à un club
|
|
|
|
|
* est associé à un jour de la semaine (numéro du jour dans la semaine : 0 = lundi, 6 = dimanche).
|
|
|
|
|
"""
|
|
|
|
|
Un cours est défini par :
|
|
|
|
|
* une heure de début et une heure de fin,
|
|
|
|
|
* une date de début et une date de fin (un cours est considéré comme donné hebdromadairement entre
|
|
|
|
|
ces deux dates) (hérite de la classe `Temporizable`)
|
|
|
|
|
* est associé à un ou plusieurs entraineurs,
|
|
|
|
|
* est associé à un club
|
|
|
|
|
* est associé à un jour de la semaine (numéro du jour dans la semaine : 0 = lundi, 6 = dimanche).
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Course"
|
|
|
|
|
verbose_name_plural = "Courses"
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Cours"
|
|
|
|
|
verbose_name_plural = "Cours"
|
|
|
|
|
|
|
|
|
|
DAY_CHOICE = (
|
|
|
|
|
(1, "Lundi"),
|
|
|
|
|
(2, "Mardi"),
|
|
|
|
|
(3, "Mercredi"),
|
|
|
|
|
(4, "Jeudi"),
|
|
|
|
|
(5, "Vendredi"),
|
|
|
|
|
(6, "Samedi"),
|
|
|
|
|
(7, "Dimanche"),
|
|
|
|
|
)
|
|
|
|
|
DAY_CHOICE = (
|
|
|
|
|
(1, "Lundi"),
|
|
|
|
|
(2, "Mardi"),
|
|
|
|
|
(3, "Mercredi"),
|
|
|
|
|
(4, "Jeudi"),
|
|
|
|
|
(5, "Vendredi"),
|
|
|
|
|
(6, "Samedi"),
|
|
|
|
|
(7, "Dimanche"),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
club = models.ForeignKey(
|
|
|
|
|
"location.Club", verbose_name="Club", on_delete=models.CASCADE, default=None
|
|
|
|
|
)
|
|
|
|
|
iso_day_number = models.PositiveSmallIntegerField(
|
|
|
|
|
choices=DAY_CHOICE, verbose_name="Jour"
|
|
|
|
|
)
|
|
|
|
|
hour_begin = models.TimeField(verbose_name="Heure de début")
|
|
|
|
|
hour_end = models.TimeField(verbose_name="Heure de fin")
|
|
|
|
|
season = models.ForeignKey(Season, on_delete=models.SET_NULL, null=True)
|
|
|
|
|
trainers = models.ManyToManyField(
|
|
|
|
|
User, verbose_name="Coach(es)", related_name="trainee"
|
|
|
|
|
)
|
|
|
|
|
gymnasts = models.ManyToManyField(
|
|
|
|
|
Gymnast, verbose_name="Gymnasts", related_name="courses"
|
|
|
|
|
)
|
|
|
|
|
club = models.ForeignKey(
|
|
|
|
|
"location.Club", verbose_name="Club", on_delete=models.CASCADE, default=None
|
|
|
|
|
)
|
|
|
|
|
iso_day_number = models.PositiveSmallIntegerField(
|
|
|
|
|
choices=DAY_CHOICE, verbose_name="Jour"
|
|
|
|
|
)
|
|
|
|
|
hour_begin = models.TimeField(verbose_name="Heure de début")
|
|
|
|
|
hour_end = models.TimeField(verbose_name="Heure de fin")
|
|
|
|
|
season = models.ForeignKey(Season, on_delete=models.SET_NULL, null=True)
|
|
|
|
|
trainers = models.ManyToManyField(
|
|
|
|
|
User, verbose_name="Coach(es)", related_name="trainee"
|
|
|
|
|
)
|
|
|
|
|
gymnasts = models.ManyToManyField(
|
|
|
|
|
Gymnast, verbose_name="Gymnasts", related_name="courses"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s (%s à %s)" % (
|
|
|
|
|
self.get_iso_day_number_display(),
|
|
|
|
|
self.hour_begin.strftime("%H:%M"),
|
|
|
|
|
self.hour_end.strftime("%H:%M"),
|
|
|
|
|
)
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s (%s à %s)" % (
|
|
|
|
|
self.get_iso_day_number_display(),
|
|
|
|
|
self.hour_begin.strftime("%H:%M"),
|
|
|
|
|
self.hour_end.strftime("%H:%M"),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def duration(self):
|
|
|
|
|
"""
|
|
|
|
|
Renvoie la durée d'un cours en heures
|
|
|
|
|
"""
|
|
|
|
|
date_begin = pendulum.datetime(
|
|
|
|
|
2000, 1, 1, self.hour_begin.hour, self.hour_begin.minute
|
|
|
|
|
)
|
|
|
|
|
date_end = pendulum.datetime(
|
|
|
|
|
2000, 1, 1, self.hour_end.hour, self.hour_end.minute
|
|
|
|
|
)
|
|
|
|
|
return date_end.diff(date_begin).in_hours()
|
|
|
|
|
@property
|
|
|
|
|
def duration(self):
|
|
|
|
|
"""Renvoie la durée d'un cours en heures
|
|
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
|
>>> course = Course(hour_begin=20, hour_end=22)
|
|
|
|
|
>>> course.duration
|
|
|
|
|
2
|
|
|
|
|
"""
|
|
|
|
|
date_begin = pendulum.datetime(
|
|
|
|
|
2000, 1, 1, self.hour_begin.hour, self.hour_begin.minute
|
|
|
|
|
)
|
|
|
|
|
date_end = pendulum.datetime(
|
|
|
|
|
2000, 1, 1, self.hour_end.hour, self.hour_end.minute
|
|
|
|
|
)
|
|
|
|
|
return date_end.diff(date_begin).in_hours()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Group(models.Model):
|
|
|
|
|
"""Classe représentant les groupes (Loisir, D1, D2, A, B, …).
|
|
|
|
|
"""Classe représentant les groupes (Loisir, D1, D2, A, B, …).
|
|
|
|
|
|
|
|
|
|
Un groupe appartient à un club.
|
|
|
|
|
"""
|
|
|
|
|
Un groupe appartient à un club.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Group"
|
|
|
|
|
verbose_name_plural = "Groups"
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Group"
|
|
|
|
|
verbose_name_plural = "Groups"
|
|
|
|
|
|
|
|
|
|
club = models.ForeignKey("location.Club", on_delete=models.CASCADE, default=None)
|
|
|
|
|
name = models.CharField(max_length=255)
|
|
|
|
|
acronym = models.CharField(max_length=50)
|
|
|
|
|
active = models.BooleanField(default=1)
|
|
|
|
|
season = models.CharField(
|
|
|
|
|
max_length=9,
|
|
|
|
|
default=str(timezone.now().year) + "-" + str(timezone.now().year + 1),
|
|
|
|
|
)
|
|
|
|
|
club = models.ForeignKey("location.Club", on_delete=models.CASCADE, default=None)
|
|
|
|
|
name = models.CharField(max_length=255)
|
|
|
|
|
acronym = models.CharField(max_length=50)
|
|
|
|
|
active = models.BooleanField(default=1)
|
|
|
|
|
season = models.CharField(
|
|
|
|
|
max_length=9,
|
|
|
|
|
default=str(timezone.now().year) + "-" + str(timezone.now().year + 1),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s (%s)" % (self.name, self.acronym)
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s (%s)" % (self.name, self.acronym)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Subgroup(models.Model):
|
|
|
|
|
"""Classe représentant les sous-groupes.
|
|
|
|
|
"""Classe représentant les sous-groupes.
|
|
|
|
|
|
|
|
|
|
Un sous-groupe appartient à un groupe (lui-même lié à un club).
|
|
|
|
|
Un sous-groupe appartient à un groupe (lui-même lié à un club).
|
|
|
|
|
|
|
|
|
|
De cette manière, quand un gymnaste est mis dans un sous-groupe, en remontant via le groupe,
|
|
|
|
|
nous pouvons connaître le(s) club(s) du gymnaste pour chaque saison.
|
|
|
|
|
"""
|
|
|
|
|
De cette manière, quand un gymnaste est mis dans un sous-groupe, en remontant via le groupe,
|
|
|
|
|
nous pouvons connaître le(s) club(s) du gymnaste pour chaque saison.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Subgroup"
|
|
|
|
|
verbose_name_plural = "Subgroups"
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Subgroup"
|
|
|
|
|
verbose_name_plural = "Subgroups"
|
|
|
|
|
|
|
|
|
|
name = models.CharField(max_length=255)
|
|
|
|
|
acronym = models.CharField(max_length=50)
|
|
|
|
|
group = models.ForeignKey(Group, on_delete=models.CASCADE, default=None)
|
|
|
|
|
courses = models.ManyToManyField(Course, related_name="to_subgroup")
|
|
|
|
|
gymnasts = models.ManyToManyField(
|
|
|
|
|
"people.Gymnast", related_name="to_gym", blank=True
|
|
|
|
|
)
|
|
|
|
|
active = models.BooleanField(default=1)
|
|
|
|
|
name = models.CharField(max_length=255)
|
|
|
|
|
acronym = models.CharField(max_length=50)
|
|
|
|
|
group = models.ForeignKey(Group, on_delete=models.CASCADE, default=None)
|
|
|
|
|
courses = models.ManyToManyField(Course, related_name="to_subgroup")
|
|
|
|
|
gymnasts = models.ManyToManyField(
|
|
|
|
|
"people.Gymnast", related_name="to_gym", blank=True
|
|
|
|
|
)
|
|
|
|
|
active = models.BooleanField(default=1)
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s (%s)" % (self.name, self.group.name)
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s (%s)" % (self.name, self.group.name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UnavailabilityManager(models.Manager):
|
|
|
|
|
"""Classe représentant le manager de la classe `Unavailability`.
|
|
|
|
|
"""
|
|
|
|
|
"""Classe représentant le manager de la classe `Unavailability`.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def next(self, count):
|
|
|
|
|
return self.filter(datebegin__gte=timezone.now()).order_by("datebegin")[0:count]
|
|
|
|
|
def next(self, count):
|
|
|
|
|
return self.filter(datebegin__gte=timezone.now()).order_by("datebegin")[0:count]
|
|
|
|
|
|
|
|
|
|
def last(self, count):
|
|
|
|
|
return self.filter(dateend__lte=timezone.now()).order_by("-dateend")[0:count]
|
|
|
|
|
def last(self, count):
|
|
|
|
|
return self.filter(dateend__lte=timezone.now()).order_by("-dateend")[0:count]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Unavailability(Markdownizable, Temporizable):
|
|
|
|
|
"""Classe représentant les indisponibilités.
|
|
|
|
|
"""
|
|
|
|
|
"""Classe représentant les indisponibilités.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Indisponibilité"
|
|
|
|
|
verbose_name_plural = "Indisponibilités"
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Indisponibilité"
|
|
|
|
|
verbose_name_plural = "Indisponibilités"
|
|
|
|
|
|
|
|
|
|
course = models.ManyToManyField(Course, related_name="unavailability")
|
|
|
|
|
course = models.ManyToManyField(Course, related_name="unavailability")
|
|
|
|
|
|
|
|
|
|
objects = UnavailabilityManager()
|
|
|
|
|
objects = UnavailabilityManager()
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "du %s au %s" % (self.datebegin, self.dateend)
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "du %s au %s" % (self.datebegin, self.dateend)
|
|
|
|
|
|
|
|
|
|
def save(self, *args, **kwargs):
|
|
|
|
|
self.checkdates()
|
|
|
|
|
def save(self, *args, **kwargs):
|
|
|
|
|
self.checkdates()
|
|
|
|
|
|
|
|
|
|
super().save(*args, **kwargs)
|
|
|
|
|
super().save(*args, **kwargs)
|
|
|
|
|
|
|
|
|
|
def checkdates(self):
|
|
|
|
|
if self.dateend is None and self.datebegin is not None:
|
|
|
|
|
self.dateend = self.datebegin
|
|
|
|
|
def checkdates(self):
|
|
|
|
|
if self.dateend is None and self.datebegin is not None:
|
|
|
|
|
self.dateend = self.datebegin
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Training(models.Model):
|
|
|
|
|
"""Classe représentant les entraînements.
|
|
|
|
|
"""Classe représentant les entraînements.
|
|
|
|
|
|
|
|
|
|
Un entraînement est une occurence d'un cours pendant lequel des gmnastes sont présents.
|
|
|
|
|
Un entraînement est une occurence d'un cours pendant lequel des gmnastes sont présents.
|
|
|
|
|
|
|
|
|
|
Un objet de cette classe lie donc un cours et un gymnaste à une date donnée.
|
|
|
|
|
"""
|
|
|
|
|
Un objet de cette classe lie donc un cours et un gymnaste à une date donnée.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Training"
|
|
|
|
|
verbose_name_plural = "Trainings"
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Training"
|
|
|
|
|
verbose_name_plural = "Trainings"
|
|
|
|
|
|
|
|
|
|
gymnast = models.ForeignKey(
|
|
|
|
|
"people.Gymnast",
|
|
|
|
|
verbose_name="Gymnast",
|
|
|
|
|
on_delete=models.CASCADE,
|
|
|
|
|
default=None,
|
|
|
|
|
related_name="trainings",
|
|
|
|
|
)
|
|
|
|
|
course = models.ForeignKey(
|
|
|
|
|
Course, verbose_name="Course", on_delete=models.CASCADE, default=None
|
|
|
|
|
)
|
|
|
|
|
trainingdate = models.DateField(verbose_name="Date")
|
|
|
|
|
gymnast = models.ForeignKey(
|
|
|
|
|
"people.Gymnast",
|
|
|
|
|
verbose_name="Gymnast",
|
|
|
|
|
on_delete=models.CASCADE,
|
|
|
|
|
default=None,
|
|
|
|
|
related_name="trainings",
|
|
|
|
|
)
|
|
|
|
|
course = models.ForeignKey(
|
|
|
|
|
Course, verbose_name="Course", on_delete=models.CASCADE, default=None
|
|
|
|
|
)
|
|
|
|
|
trainingdate = models.DateField(verbose_name="Date")
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s - %s, %s" % (self.trainingdate, self.course, self.gymnast)
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s - %s, %s" % (self.trainingdate, self.course, self.gymnast)
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def create(gymnast, course, trainingdate):
|
|
|
|
|
t = Training()
|
|
|
|
|
t.gymnast = gymnast
|
|
|
|
|
t.course = course
|
|
|
|
|
t.trainingdate = trainingdate
|
|
|
|
|
t.save()
|
|
|
|
|
return t
|
|
|
|
|
@staticmethod
|
|
|
|
|
def create(gymnast, course, trainingdate):
|
|
|
|
|
t = Training()
|
|
|
|
|
t.gymnast = gymnast
|
|
|
|
|
t.course = course
|
|
|
|
|
t.trainingdate = trainingdate
|
|
|
|
|
t.save()
|
|
|
|
|
return t
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Round(Markdownizable):
|
|
|
|
|
"""Classe représentant les passages des élèves lors d'un entrainement.
|
|
|
|
|
"""Classe représentant les passages des élèves lors d'un entrainement.
|
|
|
|
|
|
|
|
|
|
Chaque record représente un passage. Il est donc lié à un record de la classe `Training`.
|
|
|
|
|
"""
|
|
|
|
|
Chaque record représente un passage. Il est donc lié à un record de la classe `Training`.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Round"
|
|
|
|
|
verbose_name_plural = "Rounds"
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Round"
|
|
|
|
|
verbose_name_plural = "Rounds"
|
|
|
|
|
|
|
|
|
|
EVALUATION_CHOICES = (
|
|
|
|
|
(0, "- -"),
|
|
|
|
|
(1, "- +"),
|
|
|
|
|
(2, "+ -"),
|
|
|
|
|
(3, "+ +"),
|
|
|
|
|
)
|
|
|
|
|
EVALUATION_CHOICES = (
|
|
|
|
|
(0, "- -"),
|
|
|
|
|
(1, "- +"),
|
|
|
|
|
(2, "+ -"),
|
|
|
|
|
(3, "+ +"),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
training = models.ForeignKey(
|
|
|
|
|
Training, on_delete=models.CASCADE, default=None, related_name="rounds"
|
|
|
|
|
)
|
|
|
|
|
educative = models.ForeignKey(
|
|
|
|
|
"objective.Educative",
|
|
|
|
|
on_delete=models.CASCADE,
|
|
|
|
|
default=None,
|
|
|
|
|
blank=True,
|
|
|
|
|
null=True,
|
|
|
|
|
)
|
|
|
|
|
round_information = models.CharField(max_length=255, blank=True, null=True)
|
|
|
|
|
round_number = models.PositiveSmallIntegerField(blank=True, null=True)
|
|
|
|
|
gymnast_evaluation = models.PositiveSmallIntegerField(
|
|
|
|
|
choices=EVALUATION_CHOICES, blank=True, null=True
|
|
|
|
|
)
|
|
|
|
|
coach_evaluation = models.PositiveSmallIntegerField(blank=True, null=True)
|
|
|
|
|
coachid = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)
|
|
|
|
|
nb_of_realisation = models.PositiveSmallIntegerField(blank=True, null=True)
|
|
|
|
|
nb_of_success = models.PositiveSmallIntegerField(blank=True, null=True)
|
|
|
|
|
is_important = models.BooleanField(default=False)
|
|
|
|
|
training = models.ForeignKey(
|
|
|
|
|
Training, on_delete=models.CASCADE, default=None, related_name="rounds"
|
|
|
|
|
)
|
|
|
|
|
educative = models.ForeignKey(
|
|
|
|
|
"objective.Educative",
|
|
|
|
|
on_delete=models.CASCADE,
|
|
|
|
|
default=None,
|
|
|
|
|
blank=True,
|
|
|
|
|
null=True,
|
|
|
|
|
)
|
|
|
|
|
round_information = models.CharField(max_length=255, blank=True, null=True)
|
|
|
|
|
round_number = models.PositiveSmallIntegerField(blank=True, null=True)
|
|
|
|
|
gymnast_evaluation = models.PositiveSmallIntegerField(
|
|
|
|
|
choices=EVALUATION_CHOICES, blank=True, null=True
|
|
|
|
|
)
|
|
|
|
|
coach_evaluation = models.PositiveSmallIntegerField(blank=True, null=True)
|
|
|
|
|
coachid = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)
|
|
|
|
|
nb_of_realisation = models.PositiveSmallIntegerField(blank=True, null=True)
|
|
|
|
|
nb_of_success = models.PositiveSmallIntegerField(blank=True, null=True)
|
|
|
|
|
is_important = models.BooleanField(default=False)
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s" % (self.round_number)
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return "%s" % (self.round_number)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PlanningLine(Markdownizable):
|
|
|
|
|
"""Classe représentant les passages prévisionnels (incubating idea).
|
|
|
|
|
"""
|
|
|
|
|
"""Classe représentant les passages prévisionnels (incubating idea).
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Planning Line"
|
|
|
|
|
verbose_name_plural = "Planning lines"
|
|
|
|
|
# ordering = ['gymnast', 'date', 'order']
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = "Planning Line"
|
|
|
|
|
verbose_name_plural = "Planning lines"
|
|
|
|
|
# ordering = ['gymnast', 'date', 'order']
|
|
|
|
|
|
|
|
|
|
gymnast = models.ForeignKey(Gymnast, on_delete=models.CASCADE, default=None)
|
|
|
|
|
date = models.DateField(verbose_name="Date")
|
|
|
|
|
order = models.PositiveSmallIntegerField()
|
|
|
|
|
todo = models.CharField(max_length=255)
|
|
|
|
|
gymnast = models.ForeignKey(Gymnast, on_delete=models.CASCADE, default=None)
|
|
|
|
|
date = models.DateField(verbose_name="Date")
|
|
|
|
|
order = models.PositiveSmallIntegerField()
|
|
|
|
|
todo = models.CharField(max_length=255)
|
|
|
|
|