From a8019b6e8d41cef1f9ead4f6dfb9e2e7ebe158c5 Mon Sep 17 00:00:00 2001 From: Gregory Trullemans Date: Sun, 30 Apr 2023 12:25:13 +0200 Subject: [PATCH] [WIP] Routine -> Combination --- jarvis/core/views.py | 4 +- ...lter_gymnasthasroutine_routine_and_more.py | 39 +++++++++++ jarvis/followup/models.py | 8 ++- jarvis/objective/admin.py | 28 ++++---- jarvis/objective/forms.py | 24 ++++--- .../migrations/0016_routine_is_routine.py | 18 +++++ ...7_combination_combinationskill_and_more.py | 16 +++++ jarvis/objective/models.py | 40 ++++++----- .../{routines => combinations}/compose.html | 0 .../{routines => combinations}/create.html | 0 .../{routines => combinations}/details.html | 0 .../{routines => combinations}/list.html | 0 jarvis/objective/views.py | 70 +++++++++++-------- .../js/admin/{routine.js => combination.js} | 0 14 files changed, 172 insertions(+), 75 deletions(-) create mode 100644 jarvis/followup/migrations/0045_alter_gymnasthasroutine_routine_and_more.py create mode 100644 jarvis/objective/migrations/0016_routine_is_routine.py create mode 100644 jarvis/objective/migrations/0017_combination_combinationskill_and_more.py rename jarvis/objective/templates/{routines => combinations}/compose.html (100%) rename jarvis/objective/templates/{routines => combinations}/create.html (100%) rename jarvis/objective/templates/{routines => combinations}/details.html (100%) rename jarvis/objective/templates/{routines => combinations}/list.html (100%) rename static/js/admin/{routine.js => combination.js} (100%) diff --git a/jarvis/core/views.py b/jarvis/core/views.py index 4ff5fbf..9f28b33 100644 --- a/jarvis/core/views.py +++ b/jarvis/core/views.py @@ -10,7 +10,7 @@ from django.views.decorators.http import require_http_methods from django.template.loader import render_to_string from django.urls import reverse -from jarvis.objective.models import Routine +from jarvis.objective.models import Combination from jarvis.profiles.models import Profile from jarvis.followup.models import Skill, Point, Chrono from jarvis.location.models import Place, Club @@ -120,7 +120,7 @@ def home(request): nb_active_gymnast = Gymnast.objects.filter(is_active=True).count() nb_event = Event.objects.all().count() nb_skill = Skill.objects.all().count() - nb_routine = Routine.objects.all().count() + nb_routine = Combination.objects.filter(is_routine=True).count() nb_score = Point.objects.all().count() nb_club = Club.objects.all().count() # percentage_week = int( diff --git a/jarvis/followup/migrations/0045_alter_gymnasthasroutine_routine_and_more.py b/jarvis/followup/migrations/0045_alter_gymnasthasroutine_routine_and_more.py new file mode 100644 index 0000000..8dafa42 --- /dev/null +++ b/jarvis/followup/migrations/0045_alter_gymnasthasroutine_routine_and_more.py @@ -0,0 +1,39 @@ +# Generated by Django 4.2 on 2023-04-30 10:14 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("objective", "0017_combination_combinationskill_and_more"), + ("followup", "0044_alter_seasoninformation_number_of_hours_per_week_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="gymnasthasroutine", + name="routine", + field=models.ForeignKey( + limit_choices_to={"is_routine": True}, + on_delete=django.db.models.deletion.CASCADE, + related_name="done_by_gymnast", + to="objective.combination", + verbose_name="Routine", + ), + ), + migrations.AlterField( + model_name="numberofroutinedone", + name="routine", + field=models.ForeignKey( + blank=True, + limit_choices_to={"is_routine": True}, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="number_of_try", + to="objective.combination", + verbose_name="Routine", + ), + ), + ] diff --git a/jarvis/followup/models.py b/jarvis/followup/models.py index bf1bca1..5c429c5 100644 --- a/jarvis/followup/models.py +++ b/jarvis/followup/models.py @@ -6,7 +6,7 @@ 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.objective.models import Educative, Skill, Combination from jarvis.location.models import Club User = get_user_model() @@ -311,9 +311,10 @@ class GymnastHasRoutine(models.Model): on_delete=models.CASCADE, ) routine = models.ForeignKey( - Routine, + Combination, verbose_name="Routine", related_name="done_by_gymnast", + limit_choices_to={"is_routine": True}, on_delete=models.CASCADE, ) routine_type = models.PositiveSmallIntegerField( @@ -343,10 +344,11 @@ class NumberOfRoutineDone(Seasonisable): on_delete=models.CASCADE, ) routine = models.ForeignKey( - Routine, + Combination, verbose_name="Routine", related_name="number_of_try", on_delete=models.SET_NULL, + limit_choices_to={"is_routine": True}, null=True, blank=True, ) diff --git a/jarvis/objective/admin.py b/jarvis/objective/admin.py index 5d6fbb8..0701beb 100644 --- a/jarvis/objective/admin.py +++ b/jarvis/objective/admin.py @@ -11,8 +11,8 @@ from django_admin_listfilter_dropdown.filters import ( from .models import ( TouchPosition, Skill, - Routine, - RoutineSkill, + Combination, + CombinationSkill, PrerequisiteClosure, ) @@ -98,8 +98,8 @@ class SkillAdmin(admin.ModelAdmin): ) -class RoutineAdmin(admin.ModelAdmin): - model = Routine +class CombinationAdmin(admin.ModelAdmin): + model = Combination fields = ( "long_label", @@ -145,7 +145,7 @@ class RoutineAdmin(admin.ModelAdmin): class Media: js = ( "js/core/jquery-3.6.0.min.js", - "js/admin/routine.js", + "js/admin/combination.js", ) # TODO: ne proposer QUE les SKILL comme educatif @@ -155,19 +155,19 @@ class RoutineAdmin(admin.ModelAdmin): # return super(Skill, self).get_related_filter(model, request) -class RoutineSkillAdmin(admin.ModelAdmin): - model = RoutineSkill +class CombinationSkillAdmin(admin.ModelAdmin): + model = CombinationSkill - list_display = ("routine", "skill", "rank") + list_display = ("combination", "skill", "rank") list_filter = (("rank", DropdownFilter),) search_fields = ( - "routine__long_label", - "routine__short_label", + "combination__long_label", + "combination__short_label", "skill__long_label", "skill__short_label", ) - ordering = ("routine",) - autocomplete_fields = ("routine", "skill") + ordering = ("combination",) + autocomplete_fields = ("combination", "skill") class PrerequisiteClosureAdmin(admin.ModelAdmin): @@ -188,6 +188,6 @@ class PrerequisiteClosureAdmin(admin.ModelAdmin): admin.site.register(TouchPosition, TouchPositionAdmin) admin.site.register(Skill, SkillAdmin) -admin.site.register(Routine, RoutineAdmin) -admin.site.register(RoutineSkill, RoutineSkillAdmin) +admin.site.register(Combination, CombinationAdmin) +admin.site.register(CombinationSkill, CombinationSkillAdmin) admin.site.register(PrerequisiteClosure, PrerequisiteClosureAdmin) diff --git a/jarvis/objective/forms.py b/jarvis/objective/forms.py index 3f112ff..4b50842 100644 --- a/jarvis/objective/forms.py +++ b/jarvis/objective/forms.py @@ -1,6 +1,6 @@ from django import forms -from .models import Skill, Routine, RoutineSkill +from .models import Skill, Combination, CombinationSkill class SkillForm(forms.ModelForm): @@ -17,9 +17,9 @@ class SkillForm(forms.ModelForm): } -class RoutineForm(forms.ModelForm): +class CombinationForm(forms.ModelForm): class Meta: - model = Routine + model = Combination fields = ( "long_label", "short_label", @@ -30,10 +30,16 @@ class RoutineForm(forms.ModelForm): ) widgets = { "long_label": forms.TextInput( - attrs={"class": "form-control", "placeholder": "Routine's long name"} + attrs={ + "class": "form-control", + "placeholder": "Combination's long name", + } ), "short_label": forms.TextInput( - attrs={"class": "form-control", "placeholder": "Routine's short name"} + attrs={ + "class": "form-control", + "placeholder": "Combination's short name", + } ), "informations": forms.Textarea( attrs={ @@ -47,16 +53,16 @@ class RoutineForm(forms.ModelForm): } -class RoutineSkillForm(forms.ModelForm): +class CombinationSkillForm(forms.ModelForm): class Meta: - model = RoutineSkill + model = CombinationSkill fields = ( - "routine", + "combination", "skill", "rank", ) widgets = { - "routine": forms.HiddenInput(), + "combination": forms.HiddenInput(), "skill": forms.HiddenInput(), "rank": forms.NumberInput(), } diff --git a/jarvis/objective/migrations/0016_routine_is_routine.py b/jarvis/objective/migrations/0016_routine_is_routine.py new file mode 100644 index 0000000..b80f0c9 --- /dev/null +++ b/jarvis/objective/migrations/0016_routine_is_routine.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2 on 2023-04-29 15:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("objective", "0015_alter_skill_position"), + ] + + operations = [ + migrations.AddField( + model_name="routine", + name="is_routine", + field=models.BooleanField(default=False), + ), + ] diff --git a/jarvis/objective/migrations/0017_combination_combinationskill_and_more.py b/jarvis/objective/migrations/0017_combination_combinationskill_and_more.py new file mode 100644 index 0000000..a8864df --- /dev/null +++ b/jarvis/objective/migrations/0017_combination_combinationskill_and_more.py @@ -0,0 +1,16 @@ +# Generated by Django 4.2 on 2023-04-30 10:14 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("objective", "0016_routine_is_routine"), + ] + + operations = [ + migrations.RenameModel("Routine", "Combination"), + migrations.RenameModel("RoutineSkill", "CombinationSkill"), + ] diff --git a/jarvis/objective/models.py b/jarvis/objective/models.py index 43d4ec9..56d8f4c 100644 --- a/jarvis/objective/models.py +++ b/jarvis/objective/models.py @@ -1,5 +1,5 @@ from django.db import models -from django.db.models import Q, Count +from django.db.models import Q from jarvis.tools.models import Markdownizable, max_even_if_none @@ -244,20 +244,22 @@ class Skill(Educative): return f"{self.long_label} ({self.notation})" -class Routine(Educative): +class Combination(Educative): """ - Classe représentant une série (enchainement de plusieurs figures). Elle hérite de la classe + Classe représentant une série (c-à-d. un enchainement de plusieurs figures). Elle hérite de la classe `Educative`. + TODO: il faudrait changer le nom de la classe en "Combination". """ class Meta: - verbose_name = "Routine" - verbose_name_plural = "Routines" + verbose_name = "Combination" + verbose_name_plural = "Combinations" jumps = models.ManyToManyField( - Skill, through="RoutineSkill", verbose_name="routine" + Skill, through="CombinationSkill", verbose_name="combination" ) is_active = models.BooleanField(default=True) + is_routine = models.BooleanField(default=False) is_competitive = models.BooleanField(default=False) def __str__(self): @@ -267,15 +269,15 @@ class Routine(Educative): """Calcule les informations (rank, niveau, ages, …) d'une routine.""" rank = 0 level = 0 - age_boy_with_help = 0 - age_girl_with_help = 0 - age_boy_without_help = 0 - age_girl_without_help = 0 + difficulty = 0 age_boy_chained = 0 age_girl_chained = 0 + age_boy_with_help = 0 + age_girl_with_help = 0 age_boy_masterised = 0 age_girl_masterised = 0 - difficulty = 0 + age_boy_without_help = 0 + age_girl_without_help = 0 is_competitive = True for skill_link in self.skill_links.all(): @@ -392,21 +394,27 @@ class Routine(Educative): ).exists() -class RoutineSkill(models.Model): +class CombinationSkill(models.Model): """ Classe de liaison permettant de liée une figure à une série. (relation n-n) + TODO: devrait être renommée en "CombinationSkill". """ class Meta: ordering = ("rank",) - routine = models.ForeignKey( - Routine, on_delete=models.CASCADE, default=None, related_name="skill_links" + combination = models.ForeignKey( + Combination, + on_delete=models.CASCADE, + default=None, + related_name="skill_links", ) skill = models.ForeignKey( - Skill, on_delete=models.CASCADE, default=None, related_name="routine_links" + Skill, on_delete=models.CASCADE, default=None, related_name="combination_links" ) rank = models.PositiveSmallIntegerField() def __str__(self): - return f"{self.rank} - {self.routine.short_label} : {self.skill.short_label}" + return ( + f"{self.rank} - {self.combination.short_label} : {self.skill.short_label}" + ) diff --git a/jarvis/objective/templates/routines/compose.html b/jarvis/objective/templates/combinations/compose.html similarity index 100% rename from jarvis/objective/templates/routines/compose.html rename to jarvis/objective/templates/combinations/compose.html diff --git a/jarvis/objective/templates/routines/create.html b/jarvis/objective/templates/combinations/create.html similarity index 100% rename from jarvis/objective/templates/routines/create.html rename to jarvis/objective/templates/combinations/create.html diff --git a/jarvis/objective/templates/routines/details.html b/jarvis/objective/templates/combinations/details.html similarity index 100% rename from jarvis/objective/templates/routines/details.html rename to jarvis/objective/templates/combinations/details.html diff --git a/jarvis/objective/templates/routines/list.html b/jarvis/objective/templates/combinations/list.html similarity index 100% rename from jarvis/objective/templates/routines/list.html rename to jarvis/objective/templates/combinations/list.html diff --git a/jarvis/objective/views.py b/jarvis/objective/views.py index 61bee0d..e95ba76 100644 --- a/jarvis/objective/views.py +++ b/jarvis/objective/views.py @@ -9,13 +9,13 @@ from jarvis.people.models import Gymnast from .forms import ( SkillForm, - RoutineForm, - RoutineSkillForm, + CombinationForm, + CombinationSkillForm, ) from .models import ( Skill, - Routine, - RoutineSkill, + Combination, + CombinationSkill, PrerequisiteClosure, ) @@ -182,22 +182,24 @@ def routine_listing(request, gymnast_id=None): gymnast = None pattern = request.GET.get("pattern", None) if pattern: - routine_list = Routine.objects.filter( + routine_list = Combination.objects.filter(is_routine=True).filter( Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern) ) else: if gymnast_id: - routine_list = Routine.objects.filter(done_by_gymnast__gymnast=gymnast_id) + routine_list = Combination.objects.filter(is_routine=True).filter( + done_by_gymnast__gymnast=gymnast_id + ) gymnast = Gymnast.objects.get(pk=gymnast_id) else: - routine_list = Routine.objects.all() + routine_list = Combination.objects.filter(is_routine=True) context = { "routine_list": routine_list, "gymnast_id": gymnast_id, "gymnast": gymnast, } - return render(request, "routines/list.html", context) + return render(request, "combinations/list.html", context) @login_required @@ -209,8 +211,12 @@ def routine_lookup(request): pattern = request.POST.get("pattern", None) if pattern is not None and len(pattern) >= 3: - results = Routine.objects.filter( - Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern) + results = ( + Combination() + .objects.filter(is_routine=True) + .filter( + Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern) + ) ) place_list = [{"id": x.id, "label": str(x)} for x in results] @@ -226,42 +232,44 @@ def routine_details(request, routine_id): routine_id int identifiant d'une routine """ - routine = get_object_or_404(Routine, pk=routine_id) + routine = get_object_or_404(Combination, pk=routine_id) routine.compute_informations() context = {"routine": routine, "skill_link_list": routine.skill_links.all()} - return render(request, "routines/details.html", context) + return render(request, "combinations/details.html", context) @login_required @require_http_methods(["GET", "POST"]) -def routine_create_or_update(request, routine_id=None): +def routine_create_or_update(request, combination_id=None): """Création d'une série. Args: - routine_id (int): identifiant d'un object de classe . + combination_id (int): identifiant d'un object de classe . """ - if routine_id: - routine = get_object_or_404(Routine, pk=routine_id) + if combination_id: + combination = get_object_or_404(Combination, pk=combination_id) else: - routine = None + combination = None if request.method == "POST": - form = RoutineForm(request.POST, instance=routine) + form = CombinationForm(request.POST, instance=combination) if form.is_valid(): - routine = form.save() + combination = form.save() # ici faire un FOR skill in form_skills_list: # record.save() # ca sauve le record dans la table RoutineSkill # something like this : http://stackoverflow.com/questions/3074938/django-m2m-form-save-through-table # TO_FRED : can you help me ? - return HttpResponseRedirect(reverse("routine_details", args=(routine.pk,))) + return HttpResponseRedirect( + reverse("routine_details", args=(combination.pk,)) + ) else: - return render(request, "routines/create.html", {"form": form}) + return render(request, "combinations/create.html", {"form": form}) - form = RoutineForm(instance=routine) - context = {"form": form, "routine_id": routine_id} - return render(request, "routines/create.html", context) + form = CombinationForm(instance=combination) + context = {"form": form, "routine_id": combination_id} + return render(request, "combinations/create.html", context) @login_required @@ -271,7 +279,7 @@ def compose_routine(request, routine_id): Récupère une routine et les sauts associés. """ - routine = get_object_or_404(Routine, pk=routine_id) + routine = get_object_or_404(Combination, pk=routine_id) skill_link_list = routine.skill_links.all() skill_list = Skill.objects.all() context = { @@ -280,7 +288,7 @@ def compose_routine(request, routine_id): "number_of_skill": skill_link_list.count(), "skill_list": skill_list, } - return render(request, "routines/compose.html", context) + return render(request, "combinations/compose.html", context) @require_http_methods(["POST"]) @@ -289,14 +297,14 @@ def link_skill_to_routine(request): Recoit trois informations permettant de lier complètement un saut à une routine """ data = { - "routine": get_object_or_404(Routine, pk=request.POST.get("routine_id", 0)), + "routine": get_object_or_404(Combination, pk=request.POST.get("routine_id", 0)), "skill": get_object_or_404(Skill, pk=request.POST.get("skill_id", 0)), "rank": request.POST.get("rank", 0), } - form = RoutineSkillForm(data) + form = CombinationSkillForm(data) if form.is_valid(): - link, created = RoutineSkill.objects.get_or_create( + link, created = CombinationSkill.objects.get_or_create( routine=form.cleaned_data["routine"], skill=form.cleaned_data["skill"], rank=form.cleaned_data["rank"], @@ -313,9 +321,9 @@ def unlink_skill_from_routine(request): """ order = request.POST.get("order", None) routine_id = request.POST.get("routine_id", None) - routine = get_object_or_404(Routine, pk=routine_id) + routine = get_object_or_404(Combination, pk=routine_id) try: - RoutineSkill.objects.get(routine=routine, rank=order).delete() + CombinationSkill.objects.get(routine=routine, rank=order).delete() except Exception: return HttpResponse(409) diff --git a/static/js/admin/routine.js b/static/js/admin/combination.js similarity index 100% rename from static/js/admin/routine.js rename to static/js/admin/combination.js