from django.db import models from datetime import date import pendulum from tools.models import Markdownizable from location.models import Club from objective.models import Skill from django.db.models import Q, Count, Min class Gymnast(Markdownizable): """Représente un gymnaste. Un gymnaste peut être actif ou inactif. """ class Meta: verbose_name = "Gymnast" verbose_name_plural = "Gymnasts" GENDER_CHOICES = ((0, "Male"), (1, "Female")) 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" ) trainings_by_week = models.PositiveSmallIntegerField(verbose_name="# Training by week") hours_by_week = models.PositiveSmallIntegerField(verbose_name="# Hours by week") def __str__(self): return u"%s, %s" % (self.last_name, self.first_name) @property def next_birthday_in_days(self): now = pendulum.now() return self.next_birthday.diff(now).in_days() @property def age(self): """ Renvoie l'âge d'un gymnaste. """ today = date.today() return ( today.year - self.birthdate.year - ((today.month, today.day) < (self.birthdate.month, self.birthdate.day)) ) @property def next_age(self): """ Renvoie l'âge prochain du gymnaste. """ return (self.age) + 1 def min_rank_skill(self): tmp = Skill.objects.filter(known_by__gymnast=self.id).order_by("rank").values('rank')[:1] if tmp: min_rank = tmp[0]['rank'] else: min_rank = 0 return min_rank def max_rank_skill(self): tmp = Skill.objects.filter(known_by__gymnast=self.id).order_by( "-rank" ).values('rank')[:1] if tmp: max_rank = tmp[0]['rank'] else: max_rank = 0 return max_rank def known_skill_by_rank(self): """ Renvoie le nombre de Skill qu'un gymnast sait faire par rang """ nb_known_skill_by_rank = ( Skill.objects.values("rank") .filter(known_by__gymnast=self.id) .order_by("rank") .annotate(nb_known_skill=Count("id")) ) return nb_known_skill_by_rank def max_level_skill(self): tmp = Skill.objects.filter(known_by__gymnast=self.id).order_by( "-level" ).values('level')[:1] if tmp: max_level = tmp[0]['level'] else: max_level = 0 return max_level def nb_known_skill_by_level(self): nb_known_skill_by_level = ( Skill.objects.values("level") .filter(known_by__gymnast=self.id) .order_by("level") .annotate(nb_known_skill=Count("id")) ) return nb_known_skill_by_level def get_informations_from_level(self): """ Calcule toutes les statistiques par rapport au niveau. 1. on va chercher le niveau maximum de skill que le gymnast sait faire 2. on va chercher le nombre de skill par niveau que le gymnast sait faire 3. si le niveau max est supérieur à 0 OUI: pour chaque skill du 2. - si le niveau du skill est le même que ... je sais pas, je comprends plus... NON: """ context = {} max_level_skill = self.max_level_skill() context["max_level_skill"] = max_level_skill nb_known_skill_by_level = self.nb_known_skill_by_level() gymnast_nb_known_skills = self.known_skills.distinct('skill').count() if max_level_skill > 0: context["total_skill"] = Skill.nb_skill_lte_level(max_level_skill) nb_skill_by_level = Skill.nb_skill_by_level(max_level_skill) j = 0 percentages = [] for skill in nb_skill_by_level: tmp = None if skill["level"] == nb_known_skill_by_level[j]["level"]: if skill["nb_skill"] != nb_known_skill_by_level[j]["nb_known_skill"]: tmp = ( skill["level"], skill["nb_skill"], nb_known_skill_by_level[j]["nb_known_skill"], int( (nb_known_skill_by_level[j]["nb_known_skill"] / skill["nb_skill"]) * 100 ), ) j += 1 else: tmp = (skill["level"], skill["nb_skill"], 0, 0) if tmp: percentages.append(tmp) context["percentages"] = percentages # 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) context["skill_by_level"] = Skill.objects.filter( level__lte=context["max_level_skill"] ).exclude(known_by__gymnast=self.id) # Liste des Skill que le gymnaste ne sais PAS faire (ayant un niveau plus grand que le niveau max du gym) context["unknown_skill"] = Skill.objects.filter( level__gt=context["max_level_skill"] ).exclude(known_by__gymnast=self.id) else: tmp = Skill.objects.all() context["total_skill"] = tmp.count() context["unknown_skill"] = tmp # Calcul des statistiques if context["total_skill"] != 0: context["completude"] = "%s%%" % ( int((gymnast_nb_known_skills / context["total_skill"]) * 100) ) context["evaluated_level"] = int( context["max_level_skill"] * (gymnast_nb_known_skills / context["total_skill"]) ) else: context["completude"] = 0 context["evaluated_level"] = 0 return context def get_informations_from_rank(self): """ Calcule toutes les statistiques des skills par rapport au rang du gymnaste. """ context = {} min_rank_skill = self.min_rank_skill() max_rank_skill = self.max_rank_skill() context["max_rank_skill"] = max_rank_skill nb_known_skill_by_rank = self.known_skill_by_rank() gymnast_nb_known_skills = self.known_skills.distinct('skill').count() if max_rank_skill > 0: context["total_skill"] = Skill.nb_skill_lte_rank(max_rank_skill) nb_skill_by_rank = Skill.nb_skill_by_rank(max_rank_skill) j = 0 percentages = [] for skill in nb_skill_by_rank: # les deux lignes ci-dessous doivent partir if j >= nb_known_skill_by_rank.count(): break tmp = None if skill["rank"] == nb_known_skill_by_rank[j]["rank"]: if skill["nb_skill"] != nb_known_skill_by_rank[j]["nb_known_skill"]: tmp = ( skill["rank"], skill["nb_skill"], nb_known_skill_by_rank[j]["nb_known_skill"], int( (nb_known_skill_by_rank[j]["nb_known_skill"] / skill["nb_skill"]) * 100 ), ) j += 1 else: tmp = (skill["rank"], skill["nb_skill"], 0, 0) if tmp: percentages.append(tmp) context["percentages"] = percentages # 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) context["skill_by_rank"] = Skill.objects.filter( level__lte=context["max_rank_skill"] ).exclude(known_by__gymnast=self.id) # Liste des Skill que le gymnaste ne sais PAS faire (ayant un niveau # plus grand que le niveau max du gym) context["unknown_skill"] = Skill.objects.filter( level__gt=context["max_rank_skill"] ).exclude(known_by__gymnast=self.id) else: tmp = Skill.objects.all() context["unknown_skill"] = tmp context["total_skill"] = tmp.count() # Calcul des statistiques if context["total_skill"] != 0: context["completude"] = "%s%%" % ( int((gymnast_nb_known_skills / context["total_skill"]) * 100) ) context["evaluated_level"] = (min_rank_skill - 1) + ( int(context["max_rank_skill"] * (gymnast_nb_known_skills / context["total_skill"])) ) else: context["completude"] = 0 context["evaluated_level"] = 0 return context