[WIP] Review objectives #36
|
@ -12,7 +12,6 @@ from .models import (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TouchPositionAdmin(admin.ModelAdmin):
|
class TouchPositionAdmin(admin.ModelAdmin):
|
||||||
model = TouchPosition
|
model = TouchPosition
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
# coding=UTF-8
|
"""Formulaires d'édition des éducatifs, séries et compétences."""
|
||||||
|
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from datetime import date
|
|
||||||
from .models import Routine, Routine_Skill, Chrono
|
from .models import Routine, Routine_Skill, Chrono
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,10 +14,10 @@ class RoutineForm(forms.ModelForm):
|
||||||
widgets = {
|
widgets = {
|
||||||
# Champs obligatoires de la classe mère.
|
# Champs obligatoires de la classe mère.
|
||||||
"longLabel": forms.TextInput(
|
"longLabel": forms.TextInput(
|
||||||
attrs={"class": "form-control", "placeholder": "Routine's long name"}
|
attrs={"class": "form-control", "placeholder": "Routine long name"}
|
||||||
),
|
),
|
||||||
"shortLabel": forms.TextInput(
|
"shortLabel": forms.TextInput(
|
||||||
attrs={"class": "form-control", "placeholder": "Routine's short name"}
|
attrs={"class": "form-control", "placeholder": "Routine short name"}
|
||||||
),
|
),
|
||||||
"difficulty": forms.HiddenInput(),
|
"difficulty": forms.HiddenInput(),
|
||||||
"level": forms.HiddenInput(),
|
"level": forms.HiddenInput(),
|
||||||
|
|
|
@ -27,26 +27,26 @@ class Educative(Markdownizable):
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Educatif"
|
verbose_name = "Educatif"
|
||||||
verbose_name_plural = "Educatifs"
|
verbose_name_plural = "Educatifs"
|
||||||
ordering = ["longLabel", "shortLabel"] # 'level',
|
ordering = ["longLabel", "shortLabel"]
|
||||||
|
|
||||||
longLabel = models.CharField(max_length = 255, verbose_name = "Long Name")
|
longLabel = models.CharField(max_length=255, verbose_name="Long Name")
|
||||||
shortLabel = models.CharField(max_length = 255, verbose_name = "Short Name")
|
shortLabel = models.CharField(max_length=255, verbose_name="Short Name")
|
||||||
difficulty = models.DecimalField(
|
difficulty = models.DecimalField(
|
||||||
max_digits = 3, decimal_places = 1, verbose_name = "Difficulty"
|
max_digits=3, decimal_places=1, verbose_name="Difficulty"
|
||||||
)
|
)
|
||||||
level = models.PositiveSmallIntegerField(verbose_name = "Level", default = 0)
|
level = models.PositiveSmallIntegerField(verbose_name="Level", default=0)
|
||||||
rank = models.PositiveSmallIntegerField(verbose_name = "Rank", default = 0)
|
rank = models.PositiveSmallIntegerField(verbose_name="Rank", default=0)
|
||||||
educative = models.ManyToManyField(
|
educative = models.ManyToManyField(
|
||||||
"self", related_name = "educativeOf", blank = True, symmetrical = False
|
"self", related_name="educativeOf", blank=True, symmetrical=False
|
||||||
)
|
)
|
||||||
prerequisite = models.ManyToManyField(
|
prerequisite = models.ManyToManyField(
|
||||||
"self", related_name = "prerequisiteOf", blank = True, symmetrical = False
|
"self", related_name="prerequisiteOf", blank=True, symmetrical=False
|
||||||
)
|
)
|
||||||
ageBoy = models.PositiveSmallIntegerField(
|
ageBoy = models.PositiveSmallIntegerField(
|
||||||
blank = True, null = True, verbose_name = "Boy's age"
|
blank=True, null=True, verbose_name="Boy's age"
|
||||||
)
|
)
|
||||||
ageGirl = models.PositiveSmallIntegerField(
|
ageGirl = models.PositiveSmallIntegerField(
|
||||||
blank = True, null = True, verbose_name = "Girl's age"
|
blank=True, null=True, verbose_name="Girl's age"
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -59,8 +59,9 @@ class Educative(Markdownizable):
|
||||||
|
|
||||||
|
|
||||||
class TouchPosition(models.Model):
|
class TouchPosition(models.Model):
|
||||||
"""
|
"""Représentation des différentes positions d'arrivée et de départ en trampoline.
|
||||||
Classe représentant les différentes position d'arrivée/départ (landing position) en trampoline.
|
|
||||||
|
Cette classe fait référence aux *landing positions*.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -68,10 +69,10 @@ class TouchPosition(models.Model):
|
||||||
verbose_name_plural = "Landings"
|
verbose_name_plural = "Landings"
|
||||||
ordering = ["longLabel", "shortLabel", "default", "competition"]
|
ordering = ["longLabel", "shortLabel", "default", "competition"]
|
||||||
|
|
||||||
longLabel = models.CharField(max_length = 30, verbose_name = "Nom long")
|
longLabel = models.CharField(max_length=30, verbose_name="Nom long")
|
||||||
shortLabel = models.CharField(max_length = 15, verbose_name = "Nom court")
|
shortLabel = models.CharField(max_length=15, verbose_name="Nom court")
|
||||||
competition = models.BooleanField(verbose_name = "Compétition")
|
competition = models.BooleanField(verbose_name="Compétition")
|
||||||
default = models.BooleanField(verbose_name = "Défaut")
|
default = models.BooleanField(verbose_name="Défaut")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s" % (self.longLabel)
|
return "%s" % (self.longLabel)
|
||||||
|
@ -95,17 +96,6 @@ class Skill(Educative):
|
||||||
* Une position d'arrivée
|
* Une position d'arrivée
|
||||||
* Un type de rotation
|
* Un type de rotation
|
||||||
|
|
||||||
Remarks:
|
|
||||||
* Notation et simply_notation ?
|
|
||||||
* A quoi correspond la `position`, sachant qu'on a déjà la position de début et d'arrivée
|
|
||||||
* C'est quoi, le `twist`?
|
|
||||||
* Et le champ `is_competitive` ?
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
* La nomenclature n'est pas top.
|
|
||||||
rotationType -> rotation_type
|
|
||||||
simplyNotation -> simple_notation
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -128,29 +118,29 @@ class Skill(Educative):
|
||||||
(2, "Backward"),
|
(2, "Backward"),
|
||||||
)
|
)
|
||||||
|
|
||||||
position = models.CharField(max_length = 2, choices = POSITION_CHOICES)
|
position = models.CharField(max_length=2, choices=POSITION_CHOICES)
|
||||||
departure = models.ForeignKey(
|
departure = models.ForeignKey(
|
||||||
TouchPosition,
|
TouchPosition,
|
||||||
related_name = "depart_of",
|
related_name="depart_of",
|
||||||
default = get_default_position,
|
default=get_default_position,
|
||||||
verbose_name = "Take-off position",
|
verbose_name="Take-off position",
|
||||||
on_delete = models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
landing = models.ForeignKey(
|
landing = models.ForeignKey(
|
||||||
TouchPosition,
|
TouchPosition,
|
||||||
related_name = "landing_of",
|
related_name="landing_of",
|
||||||
default = get_default_position,
|
default=get_default_position,
|
||||||
verbose_name = "Landing position",
|
verbose_name="Landing position",
|
||||||
on_delete = models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
rotationType = models.PositiveSmallIntegerField(
|
rotationType = models.PositiveSmallIntegerField(
|
||||||
choices = ROTATION_CHOICES, verbose_name = "Type de rotation"
|
choices=ROTATION_CHOICES, verbose_name="Type de rotation"
|
||||||
)
|
)
|
||||||
rotation = models.PositiveSmallIntegerField(verbose_name = "1/4 de rotation")
|
rotation = models.PositiveSmallIntegerField(verbose_name="1/4 de rotation")
|
||||||
twist = models.PositiveSmallIntegerField(verbose_name = "1/2 Vrille")
|
twist = models.PositiveSmallIntegerField(verbose_name="1/2 Vrille")
|
||||||
notation = models.CharField(max_length = 25)
|
notation = models.CharField(max_length=25)
|
||||||
simplyNotation = models.CharField(max_length = 25, verbose_name = "Notation simplifiée")
|
simplyNotation = models.CharField(max_length=25, verbose_name="Notation simplifiée")
|
||||||
is_competitive = models.BooleanField(default = False)
|
is_competitive = models.BooleanField(default=False)
|
||||||
# importance = models.PositiveSmallIntegerField(default = 1)
|
# importance = models.PositiveSmallIntegerField(default = 1)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -158,8 +148,7 @@ class Skill(Educative):
|
||||||
|
|
||||||
|
|
||||||
class Routine(Educative):
|
class Routine(Educative):
|
||||||
"""Une routine représente une série, càd un enchaînement de plusieurs figures.
|
"""Une routine représente une série, càd un enchaînement de plusieurs figures."""
|
||||||
"""
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Routine"
|
verbose_name = "Routine"
|
||||||
|
@ -167,9 +156,9 @@ class Routine(Educative):
|
||||||
|
|
||||||
active = models.BooleanField()
|
active = models.BooleanField()
|
||||||
jumps = models.ManyToManyField(
|
jumps = models.ManyToManyField(
|
||||||
Skill, through = "Routine_Skill", verbose_name = "routine"
|
Skill, through="Routine_Skill", verbose_name="routine"
|
||||||
) # ceci n'est pas un vrai champ
|
) # ceci n'est pas un vrai champ (- Magritte ?)
|
||||||
is_competitive = models.BooleanField(default = False)
|
is_competitive = models.BooleanField(default=False)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s (%s)" % (self.shortLabel, self.shortLabel)
|
return "%s (%s)" % (self.shortLabel, self.shortLabel)
|
||||||
|
@ -239,10 +228,10 @@ class Routine_Skill(models.Model):
|
||||||
ordering = ("rank",)
|
ordering = ("rank",)
|
||||||
|
|
||||||
routine = models.ForeignKey(
|
routine = models.ForeignKey(
|
||||||
Routine, on_delete = models.CASCADE, default = None, related_name = "skill_links"
|
Routine, on_delete=models.CASCADE, default=None, related_name="skill_links"
|
||||||
)
|
)
|
||||||
skill = models.ForeignKey(
|
skill = models.ForeignKey(
|
||||||
Skill, on_delete = models.CASCADE, default = None, related_name = "routine_links"
|
Skill, on_delete=models.CASCADE, default=None, related_name="routine_links"
|
||||||
)
|
)
|
||||||
rank = models.PositiveSmallIntegerField()
|
rank = models.PositiveSmallIntegerField()
|
||||||
|
|
||||||
|
@ -255,10 +244,9 @@ class Routine_Skill(models.Model):
|
||||||
|
|
||||||
|
|
||||||
class Chrono(models.Model):
|
class Chrono(models.Model):
|
||||||
"""
|
"""Représentation du temps demandé à un gymnaste pour réaliser une série.
|
||||||
Classe représentant le temps réalisé par un élève pour faire une série.
|
|
||||||
|
|
||||||
.. todo:: lors de l'affichage, aller chercher les ToF contenu dans les points de compétition (avec traitement adéquat).
|
TODO: lors de l'affichage, aller chercher les ToF contenu dans les points de compétition (avec traitement adéquat).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ROUTINETYPE_CHOICE = (
|
ROUTINETYPE_CHOICE = (
|
||||||
|
@ -270,13 +258,13 @@ class Chrono(models.Model):
|
||||||
(99, "Other"),
|
(99, "Other"),
|
||||||
)
|
)
|
||||||
|
|
||||||
routine = models.ForeignKey(Routine, on_delete = models.CASCADE, default = None)
|
routine = models.ForeignKey(Routine, on_delete=models.CASCADE, default=None)
|
||||||
routine_type = models.PositiveSmallIntegerField(choices = ROUTINETYPE_CHOICE)
|
routine_type = models.PositiveSmallIntegerField(choices=ROUTINETYPE_CHOICE)
|
||||||
gymnast = models.ForeignKey(
|
gymnast = models.ForeignKey(
|
||||||
"people.gymnast", on_delete = models.CASCADE, default = None
|
"people.gymnast", on_delete=models.CASCADE, default=None
|
||||||
)
|
)
|
||||||
date = models.DateField(default = date.today, verbose_name = "Date")
|
date = models.DateField(default=date.today, verbose_name="Date")
|
||||||
score = models.DecimalField(max_digits = 5, decimal_places = 2)
|
score = models.DecimalField(max_digits=5, decimal_places=2)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s le %s : %s pour %s" % (
|
return "%s le %s : %s pour %s" % (
|
||||||
|
@ -297,17 +285,16 @@ class Chrono(models.Model):
|
||||||
|
|
||||||
|
|
||||||
class Evaluation(models.Model):
|
class Evaluation(models.Model):
|
||||||
"""
|
"""Evaluation d'un éducatif par un utilisateur.
|
||||||
Classe permettant l'évaluation des éducatifs.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
date = models.DateField(default = date.today, verbose_name = "Date")
|
date = models.DateField(default=date.today, verbose_name="Date")
|
||||||
value = models.PositiveSmallIntegerField(default = 0)
|
value = models.PositiveSmallIntegerField(default=0)
|
||||||
educative = models.ForeignKey(
|
educative = models.ForeignKey(
|
||||||
Educative,
|
Educative,
|
||||||
related_name = "depart_of",
|
related_name="depart_of",
|
||||||
verbose_name = "Take-off position",
|
verbose_name="Take-off position",
|
||||||
on_delete = models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
type_of_evaluator = models.BooleanField(default = 0)
|
type_of_evaluator = models.BooleanField(default=0)
|
||||||
evaluator = models.ForeignKey(User, null = True, on_delete = models.SET_NULL)
|
evaluator = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
|
||||||
|
|
|
@ -1,15 +1,26 @@
|
||||||
# coding=UTF-8
|
"""Tests des routines, éducatifs, compétences, ..."""
|
||||||
|
|
||||||
from django.urls import reverse
|
|
||||||
from django.test import TestCase, Client
|
from django.test import TestCase, Client
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
from .models import Routine_Skill, Routine, Skill, TouchPosition
|
from .models import Routine_Skill, Routine, Skill, TouchPosition
|
||||||
from .views import link_skill_to_routine
|
from .views import link_skill_to_routine
|
||||||
|
|
||||||
|
|
||||||
class RoutineTest(TestCase):
|
class RoutineTest(TestCase):
|
||||||
|
"""Tests unitaires liés aux séries.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
routine (Routine)
|
||||||
|
touch_position (TouchPosition)
|
||||||
|
skill (Skill)
|
||||||
|
client (django.test.Client)
|
||||||
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.routine, routine_created = Routine.objects.get_or_create(
|
"""Instancie une série (*routine*), des TouchPositions, ...
|
||||||
|
"""
|
||||||
|
self.routine, _ = Routine.objects.get_or_create(
|
||||||
longLabel="Routine test",
|
longLabel="Routine test",
|
||||||
shortLabel="Routine test",
|
shortLabel="Routine test",
|
||||||
difficulty=0,
|
difficulty=0,
|
||||||
|
@ -17,14 +28,14 @@ class RoutineTest(TestCase):
|
||||||
)
|
)
|
||||||
(
|
(
|
||||||
self.touch_position,
|
self.touch_position,
|
||||||
touch_position_created,
|
_,
|
||||||
) = TouchPosition.objects.get_or_create(
|
) = TouchPosition.objects.get_or_create(
|
||||||
longLabel="Touch test",
|
longLabel="Touch test",
|
||||||
shortLabel="Touch test",
|
shortLabel="Touch test",
|
||||||
competition=True,
|
competition=True,
|
||||||
default=True,
|
default=True,
|
||||||
)
|
)
|
||||||
self.skill, skill_created = Skill.objects.get_or_create(
|
self.skill, _ = Skill.objects.get_or_create(
|
||||||
longLabel="Skill test",
|
longLabel="Skill test",
|
||||||
shortLabel="Skill test",
|
shortLabel="Skill test",
|
||||||
difficulty=0,
|
difficulty=0,
|
||||||
|
@ -38,17 +49,19 @@ class RoutineTest(TestCase):
|
||||||
simplyNotation="t",
|
simplyNotation="t",
|
||||||
)
|
)
|
||||||
self.client = Client()
|
self.client = Client()
|
||||||
self.url_details = {
|
|
||||||
|
def test_valid_link_skill_to_routine(self):
|
||||||
|
"""Vérifie que l'association d'un Skill à une série fonctionne correctement.
|
||||||
|
"""
|
||||||
|
url_details = {
|
||||||
"routineid": self.routine.id,
|
"routineid": self.routine.id,
|
||||||
"skillid": self.skill.id,
|
"skillid": self.skill.id,
|
||||||
"order": 1,
|
"order": 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
def test_valid_link_skill_to_routine(self):
|
url = reverse("link_skill_to_routine", kwargs=url_details)
|
||||||
c = Client()
|
|
||||||
url = reverse("link_skill_to_routine", kwargs=self.url_details)
|
response = self.client.get(url)
|
||||||
response = c.get(url)
|
|
||||||
|
|
||||||
# print(response)
|
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEquals(response.status_code, 200)
|
||||||
self.assertTrue(Routine_Skill.objects.exists())
|
self.assertTrue(Routine_Skill.objects.exists())
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
# coding=UTF-8
|
"""Définition des URLs associées à l'application `objective`.
|
||||||
|
|
||||||
|
Il existe trois grandes rubriques pour cette application:
|
||||||
|
|
||||||
|
* chrono
|
||||||
|
* skill
|
||||||
|
* routine
|
||||||
|
"""
|
||||||
|
|
||||||
from django.urls import path, re_path
|
from django.urls import path, re_path
|
||||||
|
|
||||||
|
@ -46,7 +53,7 @@ routine_urlpatterns = [
|
||||||
r"suggest/",
|
r"suggest/",
|
||||||
views.suggest_routine,
|
views.suggest_routine,
|
||||||
name="suggest_routine",
|
name="suggest_routine",
|
||||||
)
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Chrono
|
# Chrono
|
||||||
|
|
|
@ -48,8 +48,7 @@ def __lookup(lookup_class, lookup_value):
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def skill_listing(request, field=None, expression=None, value=None, level=None):
|
def skill_listing(request, field=None, expression=None, value=None, level=None):
|
||||||
"""
|
"""Récupère la liste des skills suivant un pattern si celui-ci est défini.
|
||||||
Récupère la liste des skills suivant un pattern si celui-ci est définit.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pattern = None
|
pattern = None
|
||||||
|
@ -116,8 +115,7 @@ def skill_detail(request, skillid):
|
||||||
@login_required
|
@login_required
|
||||||
@require_http_methods(["POST"])
|
@require_http_methods(["POST"])
|
||||||
def linkSkillGymnast(request):
|
def linkSkillGymnast(request):
|
||||||
"""
|
"""Lie un gymnaste à une figure.
|
||||||
Lie un gymnast à une figure.
|
|
||||||
"""
|
"""
|
||||||
# utiliser un FORM pour cette fonction.
|
# utiliser un FORM pour cette fonction.
|
||||||
gymnastid = request.POST.get("gymnastid", None)
|
gymnastid = request.POST.get("gymnastid", None)
|
||||||
|
|
Loading…
Reference in New Issue