from django.db import models from django.contrib.auth import get_user_model from django.core.validators import MaxValueValidator, MinValueValidator from datetime import date from jarvis.tools.models import Markdownizable, Seasonisable from jarvis.people.models import Gymnast, GENDER_CHOICES from jarvis.planning.models import Event from jarvis.objective.models import Educative, Skill, Routine from jarvis.location.models import Club User = get_user_model() INJURY_MECHANISM_CHOICE = ( (0, "Overuse"), (1, "Trauma"), ) INJURY_BODY_SIDE_CHOICE = ( (0, "Not Applicable"), (1, "Left"), (2, "Right"), (3, "Both"), ) INJURY_TYPE_CHOICE = ( (0, "Abrasion"), (1, "Dental Injury"), (2, "Dislocation / Subluxation"), (3, "Fracture"), (4, "Haematoma / Contusion / Bruise"), (5, "Head Concussion"), (6, "Laceration"), (7, "Lesion of Meniscus or Cartilage"), (8, "Muscle Rupture / Strain / Tear / Cramps"), (9, "Nerve Injury"), (10, "Other Bone Injury"), (11, "Sprain / Ligament Injury"), (12, "Tendon Injury / Rupture / Tendinosis / Bursitis"), ) INJURY_LOCATION_CHOICE = ( (0, "Abdomen"), (1, "Ankle"), (2, "Elbow"), (3, "Foot / Toe"), (4, "Hand / Finger / Thumb"), (5, "Head / Face"), (6, "Hip / Groin"), (7, "Knee"), (8, "Low back / Sacrum / Pelvis"), (9, "Lower Leg / Achilles Tendon"), (10, "Neck / Cervical Spine"), (11, "Shoulder / Clavicula"), (12, "Sternum / Ribs / Upper back"), (13, "Thigh"), (14, "Upper arm"), (15, "Wrist"), ) ROUTINE_TYPE_CHOICE = ( (0, "Other"), (1, "Q1R1"), (2, "Q1R2"), (3, "Q2R1"), (4, "SF"), (5, "F"), (6, "Q1R1S"), (7, "Q1R2S"), (8, "Q2R1S"), (9, "SFS"), (9, "FS"), (99, "Other"), ) LEARNING_STEP_CHOICES = ( (0, "No"), (1, "With help"), (2, "Without help"), (3, "Chained"), (4, "Masterised"), ) CHRONO_TYPE_CHOICE = ( (0, "10 |"), (1, "Q1R1"), (2, "Q1R2"), (3, "Q2R1"), (4, "SF"), (5, "F"), (99, "Other"), ) SCORE_TYPE_CHOICE = ( (0, "Chrono"), (1, "ToF"), ) CATEGORY_CHOICES = { 9: "I9", 10: "I10", 11: "A11", 12: "A12", 13: "A13-14", 15: "A Junior", 18: "A Senior", 21: "B11", 22: "B12", 23: "B13-14", 24: "B Junior", 25: "B Senior", } AGE_CATOGORY_CHOICES = ( (11, "11-12"), (13, "13-14"), (15, "15-16"), (17, "17-21"), (22, "Senior"), ) NOTE_STATUS_CHOICES = ( (0, "Draft"), (1, "Published"), ) # MOD_THOMAS_TEST_CHOICES = ( # (0, "not evaluated"), # (1, "tight psoas"), # (2, "tight quadriceps"), # (3, "tight TFL"), # (4, "tight psoas en quadriceps"), # (5, "tight quadriceps en TFL"), # (6, "tight psoas en TFL"), # (7, "tight psoas en quadriceps en TFL"), # ) # LOMBO_PELVIC_AND_CERVICAL_CONTROL_CHOICES = ( # (0, "not evaluated"), # (1, "good control, good mobility"), # (2, "good control, bad mobility"), # (3, "bad control, good mobility"), # (4, "bad control, bad mobility"), # ) class Chrono(Seasonisable): """ Représente les chronos (de chandelles ou de série) enregistrés pour un(e) gymnaste. """ class Meta: verbose_name = "Chrono" verbose_name_plural = "Chronos" ordering = ["date", "gymnast"] gymnast = models.ForeignKey( Gymnast, verbose_name="gymnast", related_name="chronos", on_delete=models.CASCADE, ) chrono_type = models.PositiveSmallIntegerField( choices=CHRONO_TYPE_CHOICE, verbose_name="Routine type" ) score_type = models.PositiveSmallIntegerField( choices=SCORE_TYPE_CHOICE, verbose_name="Score type" ) score = models.DecimalField(max_digits=5, decimal_places=3) tof = models.DecimalField(max_digits=5, decimal_places=3, blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def __str__(self): return f"{self.gymnast} - {self.score} ({self.date} - {self.chrono_type})" def timeline_representation(self): return f"
  • {self.date:%d %b %Y} - New personel best {CHRONO_TYPE_CHOICE[self.chrono_type][1]}: {self.score}' ({self.tof}')
  • " @staticmethod def compute_tof(value): tof = round((value * 13) / 15, 3) * 1000 tof = tof - (tof % 5) return tof / 1000 class ChronoDetails(models.Model): """ Class permettant d'enregistrer des détails d'un chrono : le temps de chaque saut. """ class Meta: verbose_name = "Chronos Details" verbose_name_plural = "Chronos Details" ordering = ["chrono", "order"] unique_together = ["chrono", "order"] chrono = models.ForeignKey(Chrono, on_delete=models.CASCADE, related_name="details") order = models.SmallIntegerField() value = models.DecimalField(max_digits=5, decimal_places=3) class Injury(Markdownizable, Seasonisable): """ La classe `Injury` permet d'indiquer qu'un gymnaste a eu un blessure, en liaison avec un skill ou non. """ class Meta: verbose_name = "Injury" verbose_name_plural = "Injuries" # unique_together = ("gymnast", "skill", "date") gymnast = models.ForeignKey( Gymnast, verbose_name="Gymnast", related_name="injuries", on_delete=models.CASCADE, ) skill = models.ForeignKey( "objective.Skill", verbose_name="Skill", related_name="injuries", on_delete=models.SET_NULL, default=None, blank=True, null=True, ) location = models.SmallIntegerField( choices=INJURY_LOCATION_CHOICE, verbose_name="Location" ) injury_type = models.SmallIntegerField( choices=INJURY_TYPE_CHOICE, verbose_name="Type" ) body_side = models.PositiveSmallIntegerField( choices=INJURY_BODY_SIDE_CHOICE, verbose_name="Body side" ) mechanism = models.PositiveSmallIntegerField( choices=INJURY_MECHANISM_CHOICE, verbose_name="Mechanism" ) nb_week_off = models.SmallIntegerField( blank=True, null=True, verbose_name="# week off" ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def __str__(self): return f"{self.gymnast} ({self.date})" def timeline_representation(self): return f"
  • {self.date:%d %b %Y} - Accident ({self.skill}): {self.nb_week_off} (weeks off)
  • " class LearnedSkill(Seasonisable): """ Représente la capacité d'un gymnaste à savori faire un skill de la ligne d'apprentissage. """ class Meta: verbose_name = "Learned Skill" verbose_name_plural = "Learned Skills" unique_together = ("gymnast", "skill", "date", "learning_step") gymnast = models.ForeignKey( Gymnast, verbose_name="gymnast", related_name="known_skills", on_delete=models.CASCADE, ) skill = models.ForeignKey( Skill, verbose_name="Skill", related_name="known_by", on_delete=models.CASCADE, ) learning_step = models.PositiveSmallIntegerField( choices=LEARNING_STEP_CHOICES, verbose_name="Can do type" ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def __str__(self): return f"{self.gymnast} - {self.date} - {self.learning_step} - {self.skill}" def timeline_representation(self): return f"
  • {self.date:%d %b %Y} - learning of {self.skill.long_label} ({self.skill.short_label}): {LEARNING_STEP_CHOICES[self.learning_step][1]}
  • " class Plan(Seasonisable, Markdownizable): """ Classe représentant les objectifs qu'un gymnaste devra savoir faire pour une date donnée. """ class Meta: verbose_name = "Plan" verbose_name_plural = "Plans" ordering = ["date", "educative", "gymnast"] unique_together = ("gymnast", "educative") gymnast = models.ForeignKey( "people.Gymnast", verbose_name="Gymnast", related_name="todo", on_delete=models.CASCADE, ) educative = models.ForeignKey( Educative, verbose_name="Educative", related_name="plan", on_delete=models.CASCADE, ) learning_step = models.PositiveSmallIntegerField( choices=LEARNING_STEP_CHOICES, verbose_name="Can do type", default=3 ) is_done = models.BooleanField(default=0) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def __str__(self): return f"{self.gymnast} - {self.educative.short_label} - {self.date}" class Point(models.Model): """ Représente les points obtenus lors d'une compétition. """ gymnast = models.ForeignKey( Gymnast, on_delete=models.CASCADE, default=None, related_name="points" ) event = models.ForeignKey(Event, on_delete=models.CASCADE, default=None) routine_type = models.PositiveSmallIntegerField(choices=ROUTINE_TYPE_CHOICE) point_execution = models.DecimalField( max_digits=5, decimal_places=3, verbose_name="Execution" ) point_difficulty = models.DecimalField( max_digits=3, decimal_places=1, verbose_name="Difficulty" ) point_time_of_flight = models.DecimalField( max_digits=5, decimal_places=3, verbose_name="ToF" ) point_horizontal_displacement = models.DecimalField( max_digits=4, decimal_places=3, verbose_name="HD" ) penality = models.DecimalField(max_digits=3, decimal_places=1) total = models.DecimalField(max_digits=6, decimal_places=3) created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created") updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated") def __str__(self): return f"{self.gymnast} - {self.total}" class WellBeing(Markdownizable, Seasonisable): """ Représente l'état psychologique/physique d'un gymnaste """ gymnast = models.ForeignKey( Gymnast, on_delete=models.CASCADE, default=None, related_name="wellbeings" ) event = models.ForeignKey( Event, on_delete=models.SET_NULL, default=None, blank=True, null=True, related_name="wellbeings", ) mindstate = models.PositiveSmallIntegerField( verbose_name="Mindstate", validators=[MinValueValidator(1), MaxValueValidator(10)], ) sleep = models.PositiveSmallIntegerField( verbose_name="Sleep", null=True, blank=True, default=None, validators=[MinValueValidator(1), MaxValueValidator(10)], ) stress = models.PositiveSmallIntegerField( verbose_name="Stress", validators=[MinValueValidator(1), MaxValueValidator(10)], ) fatigue = models.PositiveSmallIntegerField( verbose_name="Fatigue", null=True, blank=True, default=None, validators=[MinValueValidator(1), MaxValueValidator(10)], ) muscle_soreness = models.PositiveSmallIntegerField( verbose_name="Muscle Soreness", null=True, blank=True, default=None, validators=[MinValueValidator(1), MaxValueValidator(10)], ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def __str__(self): return f"{self.gymnast} - {self.date} : {self.mindstate} | {self.sleep} | {self.stress} | {self.fatigue} | {self.muscle_soreness}" @property def get_inversed_stress(self): return 10 - self.stress @property def get_inversed_fatigue(self): return 10 - self.fatigue @property def get_inversed_muscle_soreness(self): return 10 - self.muscle_soreness class GymnastHasRoutine(models.Model): """ Classe représentant le lien entre les gymnastes et leurs séries. TODO: il y a un champ "date_begin" et un champ "date_end" --> peut hérité de Temporizable """ class Meta: verbose_name = "Gymnast Has Routine" verbose_name_plural = "Gymnast Has Routines" # unique_together() gymnast = models.ForeignKey( Gymnast, verbose_name="Gymnast", related_name="has_routine", on_delete=models.CASCADE, ) routine = models.ForeignKey( Routine, verbose_name="Routine", related_name="done_by_gymnast", on_delete=models.CASCADE, ) routine_type = models.PositiveSmallIntegerField( choices=ROUTINE_TYPE_CHOICE, verbose_name="Type", default="1" ) date_begin = models.DateField(default=date.today, verbose_name="Date begin") date_end = models.DateField(verbose_name="Date end", null=True, blank=True) def __str__(self): return f"{self.gymnast} - {self.routine_type} : {self.routine}" class NumberOfRoutineDone(Seasonisable): """ Classe permettant de suivre le nombre de séries faites par le gymnaste. """ class Meta: verbose_name = "Number of routine done" verbose_name_plural = "Number of routines done" unique_together = ("gymnast", "date", "routine_type") gymnast = models.ForeignKey( Gymnast, verbose_name="Gymnast", related_name="number_of_routine_done", on_delete=models.CASCADE, ) routine = models.ForeignKey( Routine, verbose_name="Routine", related_name="number_of_try", on_delete=models.SET_NULL, null=True, blank=True, ) routine_type = models.PositiveSmallIntegerField( choices=ROUTINE_TYPE_CHOICE, verbose_name="Type", default="1" ) number_of_try = models.PositiveSmallIntegerField( verbose_name="Number of try", default=0 ) number_of_successes = models.PositiveSmallIntegerField( verbose_name="number of successes", default=0 ) def __str__(self): return f"{self.gymnast} - {self.routine_type} ({self.routine}) : {self.number_of_try} | {self.number_of_successes}" class HeightWeight(Seasonisable): """ Classe permettant de suivre le poids et la taille d'un gymnaste """ class Meta: verbose_name = "Height & weight" verbose_name_plural = "Heights & weights" unique_together = ("gymnast", "date") gymnast = models.ForeignKey( Gymnast, verbose_name="Gymnast", related_name="height_weight", on_delete=models.CASCADE, ) height = models.DecimalField(max_digits=4, decimal_places=1, verbose_name="Height") hips_height = models.DecimalField( max_digits=4, decimal_places=1, verbose_name="Hips height", null=True, blank=True, ) weight = models.DecimalField(max_digits=4, decimal_places=1, verbose_name="Weight") def __str__(self): return f"{self.gymnast} : {self.height}/{self.hips_height} - {self.weight}" class Note(Markdownizable, Seasonisable): """ Notes relatives à un gymnaste """ gymnast = models.ForeignKey( Gymnast, on_delete=models.CASCADE, related_name="remarks" ) coach = models.ForeignKey( User, on_delete=models.SET_NULL, blank=True, null=True, related_name="notes" ) status = models.PositiveSmallIntegerField( choices=NOTE_STATUS_CHOICES, verbose_name="Status", default=0 ) title = models.CharField( default="Note of the week", verbose_name="Title", max_length=255 ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def __str__(self): return f"{self.gymnast} - {self.created_at} : {self.coach}" class Intensity(Markdownizable, Seasonisable): """Classe représentant l'intensité d'un entraînement L'intensité va prendre 4 valeurs : - la temps (en minute), - la difficulté (en 10 ème), - la quantité de figure et - le nombre de passafe. Avec ces 4 informations, la classe va en calculer 4 autres : - la difficulté moyenne par passage - la difficulté moyenne par figure - la quantité moyene de figures par passage - la quantité moyenne de figure par minute """ class Meta: verbose_name = "Intensity" verbose_name_plural = "Intensities" # unique_together = ("gymnast", "date") gymnast = models.ForeignKey( Gymnast, on_delete=models.CASCADE, related_name="intensities" ) time = models.PositiveSmallIntegerField(verbose_name="Time (in minutes)") difficulty = models.PositiveSmallIntegerField(verbose_name="Difficulty (in tenths)") quantity_of_skill = models.PositiveSmallIntegerField() number_of_passes = models.PositiveSmallIntegerField() def __str__(self): return f"{self.gymnast} - {self.date} : {self.time} - {self.difficulty} - {self.quantity_of_skill} - {self.number_of_passes}" @property def mean_difficulty_by_passe(self): return self.difficulty / self.number_of_passes @property def mean_quantity_of_skill(self): return self.quantity_of_skill / self.time @property def quantity_of_skill_by_passe(self): return self.quantity_of_skill / self.number_of_passes @property def mean_difficulty_by_skill(self): return self.difficulty / self.quantity_of_skill class SeasonInformation(models.Model): """Classe représentant l'intensité d'un entraînement""" class Meta: verbose_name = "Season Information" verbose_name_plural = "Season Informations" unique_together = ("gymnast", "season") CATEGORY_CHOICES_ARRAY = [(key, value) for key, value in CATEGORY_CHOICES.items()] gymnast = models.ForeignKey( Gymnast, on_delete=models.CASCADE, related_name="season_informations" ) season = models.CharField(max_length=9) number_of_training_sessions_per_week = models.PositiveSmallIntegerField( verbose_name="# Training/w" ) number_of_hours_per_week = models.PositiveSmallIntegerField( verbose_name="# Hours/w" ) number_of_s_and_c_sessions_per_week = models.PositiveSmallIntegerField( verbose_name="# S&C training/w", blank=True, null=True, ) number_of_s_and_c_hours_per_week = models.PositiveSmallIntegerField( verbose_name="# S&C hours/w", blank=True, null=True, ) category = models.PositiveSmallIntegerField( choices=CATEGORY_CHOICES_ARRAY, verbose_name="Category", ) club = models.ForeignKey( Club, null=True, on_delete=models.SET_NULL, related_name="season_informations" ) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"{self.gymnast} - {self.season} : {self.number_of_training_sessions_per_week} - {self.number_of_hours_per_week} - {self.category} - {self.club}" class CompetitivePointsStats(Markdownizable, Seasonisable): """Class représentant des points de références de compétitions""" TYPE_OF_STAT = ( (0, "precise"), (1, "mean + 4 * standard deviation"), (2, "mean + 2 * standard deviation"), (3, "mean + standard deviation"), (4, "mean + ½ standard deviation"), (5, "mean + ¼ standard deviation"), (6, "mean"), (7, "mean - ¼ standard deviation"), (8, "mean - ½ standard deviation"), (9, "mean - standard deviation"), (10, "mean - 2 * standard deviation"), (11, "mean - 4 * standard deviation"), ) label = models.CharField(max_length=40, null=False, blank=False) gender = models.PositiveSmallIntegerField( choices=GENDER_CHOICES, verbose_name="Gender" ) age_category = models.PositiveSmallIntegerField( choices=AGE_CATOGORY_CHOICES, verbose_name="Age category" ) statistic_type = models.PositiveSmallIntegerField( choices=TYPE_OF_STAT, verbose_name="Type of statistic" ) point_execution = models.DecimalField( max_digits=5, decimal_places=3, verbose_name="Execution" ) point_difficulty = models.DecimalField( max_digits=3, decimal_places=1, verbose_name="Difficulty" ) point_time_of_flight = models.DecimalField( max_digits=5, decimal_places=3, verbose_name="ToF" ) point_horizontal_displacement = models.DecimalField( max_digits=4, decimal_places=3, verbose_name="HD" ) total = models.DecimalField(max_digits=6, decimal_places=3) place = models.PositiveSmallIntegerField(verbose_name="Place") event = models.ForeignKey( Event, on_delete=models.SET_NULL, default=None, blank=True, null=True ) routine_type = models.PositiveSmallIntegerField(choices=ROUTINE_TYPE_CHOICE) informations = models.TextField( blank=True, null=True, help_text="Information about even or statistics (mean, standard deviation, …).", ) def __str__(self): return f"{self.age_category} - {self.gender} - {self.routine_type} : {self.total} ({self.statistic_type})" # class Stability(Seasonisable): # """Classe représentant la stabilité (Stability)""" # class Meta: # verbose_name = "Stability" # verbose_name_plural = "Stabilities" # unique_together = ["gymnast", "date"] # gymnast = models.ForeignKey( # Gymnast, on_delete=models.CASCADE, related_name="stabilitytests" # ) # anterior_chain = models.PositiveSmallIntegerField(verbose_name="Anterior Chain") # posterior_chain_left = models.PositiveSmallIntegerField( # verbose_name="Posterior Chain Left" # ) # posterior_chain_right = models.PositiveSmallIntegerField( # verbose_name="Posterior Chain Right" # ) # leg_lowering = models.PositiveSmallIntegerField( # choices=LUMBAR_STABILITY_CHOICE, # verbose_name="Leg Lowering: lumbar stability", # ) # sl_bridge = models.ManyToManyField( # SLBridge, related_name="stabilitytests", symmetrical=False # ) # side_plank_leg_raise = models.ManyToManyField( # SidePlankLegRaise, related_name="stabilitytests", symmetrical=False # ) # class QualityOfMovement(Seasonisable): # """Classe représentant les tests des qualité de mouvement (Quality of Movement)""" # class Meta: # verbose_name = "Quality Of Movement" # verbose_name_plural = "Qualities Of Movement" # unique_together = ["gymnast", "date"] # gymnast = models.ForeignKey( # Gymnast, on_delete=models.CASCADE, related_name="qualities_of_movement" # ) # overhead_squat = models.ManyToManyField( # OverheadSquat, related_name="qualities_of_movement", symmetrical=False # ) # single_leg_drop_jump = models.ManyToManyField( # DropJump, related_name="qualities_of_movement", symmetrical=False # ) # single_leg_stability_right = models.PositiveSmallIntegerField( # verbose_name="Single leg stability right" # ) # single_leg_stability_left = models.PositiveSmallIntegerField( # verbose_name="Single leg stability right" # ) # def __str__(self): # return f"{self.gymnast} - {self.date}: {self.overhead_squat}" # class Strength(Seasonisable): # """Classe représentant les tests de force (Strength)""" # class Meta: # verbose_name = "Strength" # verbose_name_plural = "Strength" # unique_together = ["gymnast", "date"] # gymnast = models.ForeignKey( # Gymnast, on_delete=models.CASCADE, related_name="strength" # ) # harmstring_left_prone = models.PositiveSmallIntegerField(null=True, blank=True) # harmstring_right_prone = models.PositiveSmallIntegerField(null=True, blank=True) # quadriceps_left_seated = models.PositiveSmallIntegerField(null=True, blank=True) # quadriceps_right_seated = models.PositiveSmallIntegerField(null=True, blank=True) # hip_adductor_left = models.PositiveSmallIntegerField(null=True, blank=True) # hip_adductor_right = models.PositiveSmallIntegerField(null=True, blank=True) # hip_abductor_left = models.PositiveSmallIntegerField(null=True, blank=True) # hip_abductor_right = models.PositiveSmallIntegerField(null=True, blank=True) # shoulder_external_rotator_left = models.PositiveSmallIntegerField( # null=True, blank=True # ) # shoulder_external_rotator_right = models.PositiveSmallIntegerField( # null=True, blank=True # ) # shoulder_internal_rotator_left = models.PositiveSmallIntegerField( # null=True, blank=True # ) # shoulder_internal_rotator_right = models.PositiveSmallIntegerField( # null=True, blank=True # ) # def __str__(self): # return f"{self.gymnast} - {self.date}" # class MobilityFlexibility(Seasonisable): # """Classe représentant les tests de Mobilité et flexibilité (Mobility and Flexibility)""" # class Meta: # verbose_name = "Mobility & Flexibility" # verbose_name_plural = "Mobility & Flexibility" # unique_together = ["gymnast", "date"] # gymnast = models.ForeignKey( # Gymnast, on_delete=models.CASCADE, related_name="mobility_fexibility" # ) # hip_internal_rotation_right = models.PositiveSmallIntegerField( # null=True, blank=True # ) # hip_internal_rotation_left = models.PositiveSmallIntegerField(null=True, blank=True) # harmstring_aket_right = models.PositiveSmallIntegerField(null=True, blank=True) # harmstring_aket_left = models.PositiveSmallIntegerField(null=True, blank=True) # elys_test_right = models.PositiveSmallIntegerField(null=True, blank=True) # elys_test_left = models.PositiveSmallIntegerField(null=True, blank=True) # bent_knee_fall_out_test_right = models.PositiveSmallIntegerField( # null=True, blank=True # ) # bent_knee_fall_out_test_left = models.PositiveSmallIntegerField( # null=True, blank=True # ) # knee_to_wall_test_right = models.PositiveSmallIntegerField(null=True, blank=True) # knee_to_wall_test_left = models.PositiveSmallIntegerField(null=True, blank=True) # shoulder_anteversion_supine_right = models.PositiveSmallIntegerField( # null=True, blank=True # ) # shoulder_anteversion_supine_left = models.PositiveSmallIntegerField( # null=True, blank=True # ) # shoulder_external_rotation_right = models.PositiveSmallIntegerField( # null=True, blank=True # ) # shoulder_external_rotation_left = models.PositiveSmallIntegerField( # null=True, blank=True # ) # shoulder_internal_rotation_right = models.PositiveSmallIntegerField( # null=True, blank=True # ) # shoulder_internal_rotation_left = models.PositiveSmallIntegerField( # null=True, blank=True # ) # functional_external_rotation_right = models.PositiveSmallIntegerField( # null=True, blank=True # ) # functional_external_rotation_left = models.PositiveSmallIntegerField( # null=True, blank=True # ) # mod_thomas_test_right = models.PositiveSmallIntegerField( # choices=MOD_THOMAS_TEST_CHOICES, default=0 # ) # mod_thomas_test_left = models.PositiveSmallIntegerField( # choices=MOD_THOMAS_TEST_CHOICES, default=0 # ) # lombo_pelvic_control = models.PositiveSmallIntegerField( # choices=LOMBO_PELVIC_AND_CERVICAL_CONTROL_CHOICES, default=0 # ) # cervical_control = models.PositiveSmallIntegerField( # choices=LOMBO_PELVIC_AND_CERVICAL_CONTROL_CHOICES, default=0 # ) # def __str__(self): # return f"{self.gymnast} - {self.date}"