Ultron/ultron/people/models.py

270 lines
9.2 KiB
Python
Raw Normal View History

2022-09-08 18:47:47 +02:00
""" Modelisation des gymnastes """
2022-01-07 18:08:39 +01:00
2022-02-06 15:44:55 +01:00
from django.contrib.auth import get_user_model
2022-01-07 18:08:39 +01:00
from django.db.models import Count
2022-02-06 15:44:55 +01:00
from django.db import models
User = get_user_model()
2021-12-09 16:53:44 +01:00
2022-02-06 15:44:55 +01:00
from datetime import date
2021-12-09 16:53:44 +01:00
import pendulum
from ultron.location.models import Club
from ultron.objective.models import Skill
from ultron.tools.models import Markdownizable
2022-09-08 18:47:47 +02:00
from ultron.objective.tools import (
nb_skill_by_type,
nb_skill_lte_type,
compute_completude,
compute_statistics_by_type,
)
2021-12-09 16:53:44 +01:00
class Gymnast(Markdownizable):
"""Représente un gymnaste.
2021-12-19 09:30:51 +01:00
Un gymnaste peut être actif ou inactif.
"""
2021-12-09 16:53:44 +01:00
class Meta:
verbose_name = "Gymnast"
verbose_name_plural = "Gymnasts"
GENDER_CHOICES = ((0, "Male"), (1, "Female"))
2022-09-07 08:56:26 +02:00
# CATEGORY_CHOICES = ((9, "I9"), (10, "I10"), (11, "A11"), (12, "A12"), (13, "A13-14"), (15, "A15-16"), (18, "Senior"))
2021-12-09 16:53:44 +01:00
2022-02-06 15:44:55 +01:00
user = models.OneToOneField(
User,
on_delete=models.SET_NULL,
related_name="gymnast",
blank=True,
null=True
)
2021-12-09 16:53:44 +01:00
last_name = models.CharField(max_length=40, null=False, blank=False)
first_name = models.CharField(max_length=25, null=False, blank=False)
birthdate = models.DateField(verbose_name="Date de naissance")
gender = models.PositiveSmallIntegerField(
choices=GENDER_CHOICES, verbose_name="Sexe"
)
is_active = models.BooleanField(default=1, verbose_name="Active")
club = models.ForeignKey(
Club, null=True, on_delete=models.SET_NULL, related_name="gymnast"
)
2022-09-07 08:56:26 +02:00
# category = models.PositiveSmallIntegerField(
# choices=CATEGORY_CHOICES, verbose_name="Category"
# )
email_trainer = models.EmailField(max_length=254, null=True, blank=True, verbose_name="Trainer's email")
2021-12-19 09:30:51 +01:00
trainings_by_week = models.PositiveSmallIntegerField(
verbose_name="# Training by week"
)
2021-12-09 16:53:44 +01:00
hours_by_week = models.PositiveSmallIntegerField(verbose_name="# Hours by week")
def __str__(self):
2022-01-07 18:08:39 +01:00
return "%s %s" % (self.first_name, self.last_name)
2021-12-09 16:53:44 +01:00
@property
def next_birthday(self):
"""Définit la prochaine date (de fête) d'anniversaire pour cette personne.
2021-12-19 09:30:51 +01:00
Returns:
Soit le jour/mois pour cette année
Soit le jour/mois pour l'année prochaine.
2021-12-09 16:53:44 +01:00
2022-09-09 13:12:45 +02:00
Example: (en supposant qu'on soit le 23/05/2019)
2021-12-19 09:30:51 +01:00
>>> from datetime import date
2022-09-09 13:12:45 +02:00
>>> gymnast = Gymnast(name='Tru', firstname='Gregg', birthdate=date(1982, 2, 5))
>>> gymnast.next_birthday()
2021-12-19 09:30:51 +01:00
Date(2020, 2, 5)
"""
2021-12-09 16:53:44 +01:00
now = pendulum.now()
this_year_birthday = pendulum.date(
now.year, self.birthdate.month, self.birthdate.day
)
if this_year_birthday.is_past():
return pendulum.date(now.year + 1, self.birthdate.month, self.birthdate.day)
return this_year_birthday
@property
def next_birthday_in_days(self):
now = pendulum.now()
return self.next_birthday.diff(now).in_days()
@property
def age(self):
2021-12-19 09:30:51 +01:00
"""Renvoie l'âge d'un gymnaste."""
2021-12-09 16:53:44 +01:00
today = date.today()
return (
today.year
- self.birthdate.year
- ((today.month, today.day) < (self.birthdate.month, self.birthdate.day))
)
@property
def next_age(self):
2021-12-19 09:30:51 +01:00
"""Renvoie l'âge prochain du gymnaste."""
2021-12-09 16:53:44 +01:00
return (self.age) + 1
2022-09-09 13:12:45 +02:00
def skill_max_for_type(self, desired_type="level"):
"""
Renvoie le niveau/rank maximum des skill que le gymnaste sait faire suivant le type passé
en paramètre.
2021-12-19 09:30:51 +01:00
2022-09-09 13:12:45 +02:00
Args:
desired_type (string): type ("level" ou "rank") des Skills désirés.
2021-12-09 16:53:44 +01:00
2022-09-09 13:12:45 +02:00
Returns:
int
Examples:
>>> from ultron.people.models import Gymnast
>>> gymnast = Gymnast.objects.get(pk=1)
>>> gymnast.skill_max_for_type("level")
1
>>> gymnast.skill_max_for_type("rank")
19
2021-12-09 16:53:44 +01:00
"""
2022-09-09 13:12:45 +02:00
if desired_type != "level" and desired_type != "rank":
return None
2021-12-09 16:53:44 +01:00
2021-12-19 09:30:51 +01:00
tmp = (
Skill.objects.filter(known_by__gymnast=self.id)
2022-09-09 13:12:45 +02:00
.order_by("-" + desired_type)
.values(desired_type)[:1]
2021-12-19 09:30:51 +01:00
)
2021-12-09 16:53:44 +01:00
if tmp:
2022-09-09 13:12:45 +02:00
skill_max = tmp[0][desired_type]
2021-12-09 16:53:44 +01:00
else:
2022-09-09 13:12:45 +02:00
skill_max = 0
2021-12-09 16:53:44 +01:00
2022-09-09 13:12:45 +02:00
return skill_max
2021-12-09 16:53:44 +01:00
2022-09-09 13:12:45 +02:00
def nb_known_skill_by_type(self, desired_type="level"):
2021-12-09 16:53:44 +01:00
"""
2022-09-09 13:12:45 +02:00
Renvoie le nombre de Skill qu'un gymnast sait faire par niveau/rang suivant le type passé
en paramètre
Args:
desired_type (string): type ("level" ou "rank") des Skills désirés.
Returns:
QuerySet
Examples:
>>> from ultron.people.models import Gymnast
>>> gymnast = Gymnast.objects.get(pk=1)
>>> gymnast.nb_known_skill_by_type("level")
<QuerySet [{'level': 0, 'nb_known_skill': 15}, {'level': 1, 'nb_known_skill': 5}]>
>>> gymnast.nb_known_skill_by_type("rank")
<QuerySet [{'rank': 1, 'nb_known_skill': 2}, {'rank': 2, 'nb_known_skill': 4}, ]>
2021-12-09 16:53:44 +01:00
"""
2022-09-09 13:12:45 +02:00
if desired_type != "level" and desired_type != "rank":
return None
nb_known_skill_by_type = (
Skill.objects.values(desired_type)
2021-12-09 16:53:44 +01:00
.filter(known_by__gymnast=self.id)
2022-09-09 13:12:45 +02:00
.order_by(desired_type)
2021-12-09 16:53:44 +01:00
.annotate(nb_known_skill=Count("id"))
)
2022-09-09 13:12:45 +02:00
return nb_known_skill_by_type
2021-12-09 16:53:44 +01:00
def unknown_skill_lte_level(self, max_level_skill):
"""
2022-01-07 19:28:33 +01:00
Liste des Skill que le gymnaste ne sait PAS faire/
Ces skills sont classé par niveau.
2021-12-09 16:53:44 +01:00
"""
2021-12-19 09:30:51 +01:00
return Skill.objects.filter(level__lte=max_level_skill).exclude(
known_by__gymnast=self.id
)
2021-12-09 16:53:44 +01:00
def unknown_skill_gt_level(self, max_level_skill):
"""
2022-01-07 19:28:33 +01:00
Liste des Skill que le gymnaste ne sait PAS faire,
classé par niveau (ayant un niveau inférieur ou égal au niveau max du gym)
2021-12-09 16:53:44 +01:00
"""
2021-12-19 09:30:51 +01:00
return Skill.objects.filter(level__gt=max_level_skill).exclude(
known_by__gymnast=self.id
)
2021-12-09 16:53:44 +01:00
def unknown_skill_lte_rank(self, max_rank_skill):
# Liste des Skill que le gymnaste ne sait PAS faire, classé par niveau
# (ayant un niveau inférieur ou égal au niveau max du gym)
2021-12-19 09:30:51 +01:00
return Skill.objects.filter(level__lte=max_rank_skill).exclude(
known_by__gymnast=self.id
)
2021-12-09 16:53:44 +01:00
def unknown_skill_gt_rank(self, max_rank_skill):
"""
2022-01-07 19:28:33 +01:00
Liste des Skill que le gymnaste ne sais PAS faire
(ayant un niveau plus grand que le niveau max du gym)
2021-12-09 16:53:44 +01:00
"""
2021-12-19 09:30:51 +01:00
return Skill.objects.filter(level__gt=max_rank_skill).exclude(
known_by__gymnast=self.id
)
2021-12-09 16:53:44 +01:00
2022-09-09 13:12:45 +02:00
def get_informations_from_type(self, desired_type="level"):
2021-12-09 16:53:44 +01:00
"""
2022-09-09 13:12:45 +02:00
Calcule toutes les statistiques par rapport au niveau/rang suivant le paramètre transmis.
2021-12-09 16:53:44 +01:00
2022-09-09 13:12:45 +02:00
1. On va chercher le niveau/rang maximum de skill que le gymnast sait faire
2. 0n va chercher le nombre de skill par niveau/rang que le gymnast sait faire
nb_known_skill_by_type = [
2022-01-07 19:28:33 +01:00
{
'level': 1,
'nb_known_skill': 1
},
{
'level': 2,
'nb_known_skill': 2
}
]
2022-09-09 13:12:45 +02:00
3. Si le niveau/rang maximum est supérieur à 0:
a. on va chercher le nombre de skill qu'il y a par niveau/rang :
2022-01-07 19:28:33 +01:00
[
{
'level': 1, 'nb_skill': 1
},
{
'level': 2, 'nb_skill': 1
}
]
2021-12-09 16:53:44 +01:00
2022-09-09 13:12:45 +02:00
b. on va chercher le nombre total des skills dont le niveau/rang est inférieur ou
égale au niveau max.
2021-12-09 16:53:44 +01:00
2022-09-09 13:12:45 +02:00
c. on calcule les statistiques du gymnaste par rapport aux skill
2021-12-09 16:53:44 +01:00
2022-09-09 13:12:45 +02:00
SINON:
on va chercher tous les Skill qui existent, on les met dans une liste et on les compte.
2021-12-09 16:53:44 +01:00
"""
2022-09-09 13:12:45 +02:00
if desired_type != "level" and desired_type != "rank":
return None
2021-12-09 16:53:44 +01:00
context = {}
2022-09-09 13:12:45 +02:00
skill_max = self.skill_max_for_type(desired_type)
cpt_known_skill_by_type = self.nb_known_skill_by_type(desired_type)
2021-12-19 09:30:51 +01:00
gymnast_nb_known_skills = self.known_skills.distinct("skill").count()
2021-12-09 16:53:44 +01:00
2022-09-09 13:12:45 +02:00
if skill_max > 0:
cpt_skill_by_type = nb_skill_by_type(skill_max, desired_type)
context["total_skill"] = nb_skill_lte_type(skill_max, desired_type)
2022-09-08 18:47:47 +02:00
context["percentages"] = compute_statistics_by_type(
2022-09-09 13:12:45 +02:00
cpt_skill_by_type, cpt_known_skill_by_type, desired_type
2021-12-19 09:30:51 +01:00
)
2022-09-09 13:12:45 +02:00
context["skill_by_level"] = self.unknown_skill_lte_level(skill_max)
context["unknown_skill"] = self.unknown_skill_gt_level(skill_max)
2021-12-09 16:53:44 +01:00
else:
tmp = Skill.objects.all()
context["total_skill"] = tmp.count()
2022-09-09 13:12:45 +02:00
context["unknown_skill"] = tmp
2021-12-09 16:53:44 +01:00
2022-09-08 18:47:47 +02:00
context["completude"], context["evaluated_level"] = compute_completude(
2022-09-09 13:12:45 +02:00
context["total_skill"], gymnast_nb_known_skills, skill_max
2021-12-19 09:30:51 +01:00
)
2021-12-09 16:53:44 +01:00
2022-09-09 13:12:45 +02:00
context["max_" + desired_type + "_skill"] = skill_max
2021-12-19 09:30:51 +01:00
return context