Blacked python file

This commit is contained in:
Gregory Trullemans 2021-12-19 09:30:51 +01:00
parent 2e23a46277
commit df753f9e76
51 changed files with 2017 additions and 996 deletions

View File

@ -18,7 +18,7 @@ steps:
{{#success build.status}} {{#success build.status}}
Ultron build {{build.number}} succeeded. Good job. Ultron build {{build.number}} succeeded. Good job.
{{else}} {{else}}
Ultron build {{build.number}} failed. Fix me please. Ultron build {{build.number}} failed. Fix me please. More info : https://drone.grimbox.be/Sulley/Ultron/{{build.number}}
{{/success}} {{/success}}
when: when:
status: status:

View File

@ -11,7 +11,7 @@
<h4 class=""><i class="icon-primary fal fa-laugh-wink"></i> Hi {{ user.username }} !</h4> <h4 class=""><i class="icon-primary fal fa-laugh-wink"></i> Hi {{ user.username }} !</h4>
</div> </div>
<div class="card-body"> <div class="card-body">
Welcome to Ultron v0.30 <span class="text-muted">(last update : 16-12-2021)</span><br /> Welcome to Ultron v0.31 <span class="text-muted">(last update : 19-12-2021)</span><br />
This application is there to help us manage the gymnasts (evolution, evaluation, ...). It is not perfect so feel free to make improvement proposals, bug reports, … by sending me an <a href="mailto:gregory@flyingacrobaticstrampoline.be">email</a>. This application is there to help us manage the gymnasts (evolution, evaluation, ...). It is not perfect so feel free to make improvement proposals, bug reports, … by sending me an <a href="mailto:gregory@flyingacrobaticstrampoline.be">email</a>.
</div> </div>
</div> </div>

View File

@ -2,85 +2,98 @@ from django.contrib import admin
from django.db.models import fields from django.db.models import fields
from config.views import search from config.views import search
from .models import Chrono, LearnedSkill, Point, Accident, MindState, GymnastHasRoutine, NumberOfRoutineDone, HeightWeight from .models import (
Chrono,
LearnedSkill,
Point,
Accident,
MindState,
GymnastHasRoutine,
NumberOfRoutineDone,
HeightWeight,
)
from django_extensions.admin import ForeignKeyAutocompleteAdmin from django_extensions.admin import ForeignKeyAutocompleteAdmin
class ChronoAdmin(ForeignKeyAutocompleteAdmin): class ChronoAdmin(ForeignKeyAutocompleteAdmin):
model = Chrono model = Chrono
list_display = ('date', 'gymnast', 'tof', 'type') list_display = ("date", "gymnast", "tof", "type")
list_filter = ('type', ) list_filter = ("type",)
# search_fields = ('gymnast', 'routine') # search_fields = ('gymnast', 'routine')
autocomplete_fields = ['gymnast'] autocomplete_fields = ["gymnast"]
related_search_fields = { related_search_fields = {"gymnast": ("last_name", "first_name")}
'gymnast': ('last_name', 'first_name')
}
class LearnedSkillAdmin(admin.ModelAdmin): class LearnedSkillAdmin(admin.ModelAdmin):
model = LearnedSkill model = LearnedSkill
list_display = ('gymnast', 'skill', 'cando', 'date') list_display = ("gymnast", "skill", "cando", "date")
list_filter = ('gymnast', 'skill', 'cando') list_filter = ("gymnast", "skill", "cando")
search_fields = ('gymnast', 'skill') search_fields = ("gymnast", "skill")
autocomplete_fields = ['gymnast', 'skill'] autocomplete_fields = ["gymnast", "skill"]
class PointAdmin(admin.ModelAdmin): class PointAdmin(admin.ModelAdmin):
model = Point model = Point
list_display = ( list_display = (
'gymnast', "gymnast",
'point_execution', "point_execution",
'point_difficulty', "point_difficulty",
'point_time_of_flight', "point_time_of_flight",
'total', "total",
) )
ordering = ('gymnast',) ordering = ("gymnast",)
list_filter = ('gymnast', 'event', 'routine_type') list_filter = ("gymnast", "event", "routine_type")
class AccidentAdmin(admin.ModelAdmin): class AccidentAdmin(admin.ModelAdmin):
model = Accident model = Accident
fields = ('date', 'gymnast', 'skill', 'informations') # educative fields = ("date", "gymnast", "skill", "informations") # educative
list_display = ('date', 'gymnast', 'skill') # educative list_display = ("date", "gymnast", "skill") # educative
list_filter = ('date',) list_filter = ("date",)
search_fields = ('date', 'gymnast') # educative search_fields = ("date", "gymnast") # educative
autocomplete_fields = ['gymnast'] # educative autocomplete_fields = ["gymnast"] # educative
class MindStateAdmin(admin.ModelAdmin): class MindStateAdmin(admin.ModelAdmin):
model = MindState model = MindState
fields = ('gymnast', 'date', 'score', 'informations') fields = ("gymnast", "date", "score", "informations")
list_display = ('date', 'gymnast', 'score') list_display = ("date", "gymnast", "score")
list_filter = ('date', 'gymnast') list_filter = ("date", "gymnast")
class GymnastHasRoutineAdmin(ForeignKeyAutocompleteAdmin): class GymnastHasRoutineAdmin(ForeignKeyAutocompleteAdmin):
model = GymnastHasRoutine model = GymnastHasRoutine
list_display = ('gymnast', 'routine', 'routine_type', 'datebegin', 'dateend') list_display = ("gymnast", "routine", "routine_type", "datebegin", "dateend")
list_filter = ('gymnast', 'routine_type') list_filter = ("gymnast", "routine_type")
search_fields = ('gymnast', 'routine') search_fields = ("gymnast", "routine")
autocomplete_fields = ('gymnast', 'routine') autocomplete_fields = ("gymnast", "routine")
class NumberOfRoutineDoneAdmin(ForeignKeyAutocompleteAdmin): class NumberOfRoutineDoneAdmin(ForeignKeyAutocompleteAdmin):
model = NumberOfRoutineDone model = NumberOfRoutineDone
list_display = ('gymnast', 'routine_type', 'date', 'number_of_successes', 'number_of_try') list_display = (
list_filter = ('gymnast', 'routine_type') "gymnast",
"routine_type",
"date",
"number_of_successes",
"number_of_try",
)
list_filter = ("gymnast", "routine_type")
class HeightWeightAdmin(ForeignKeyAutocompleteAdmin): class HeightWeightAdmin(ForeignKeyAutocompleteAdmin):
model = HeightWeight model = HeightWeight
list_display = ('gymnast', 'height', 'weight', 'date') list_display = ("gymnast", "height", "weight", "date")
list_filter = ('gymnast',) list_filter = ("gymnast",)
admin.site.register(Accident, AccidentAdmin) admin.site.register(Accident, AccidentAdmin)

View File

@ -2,5 +2,5 @@ from django.apps import AppConfig
class FollowupConfig(AppConfig): class FollowupConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField' default_auto_field = "django.db.models.BigAutoField"
name = 'ultron.followup' name = "ultron.followup"

View File

@ -5,64 +5,72 @@ from datetime import date
from django.db import models from django.db import models
from django.forms import fields, widgets from django.forms import fields, widgets
from .models import Chrono, LearnedSkill, Point, Accident, MindState, GymnastHasRoutine, HeightWeight from .models import (
Chrono,
LearnedSkill,
Point,
Accident,
MindState,
GymnastHasRoutine,
HeightWeight,
)
class ChronoForm(forms.ModelForm): class ChronoForm(forms.ModelForm):
class Meta: class Meta:
model = Chrono model = Chrono
fields = ('gymnast', 'date', 'type', 'score_type', 'score', 'tof') fields = ("gymnast", "date", "type", "score_type", "score", "tof")
widgets = { widgets = {
'gymnast': forms.HiddenInput(), "gymnast": forms.HiddenInput(),
'date': forms.TextInput( "date": forms.TextInput(
attrs={ attrs={
'class': 'form-control datepicker', "class": "form-control datepicker",
'placeholder': date.today().strftime('%Y-%m-%d'), "placeholder": date.today().strftime("%Y-%m-%d"),
'value': date.today().strftime('%Y-%m-%d'), "value": date.today().strftime("%Y-%m-%d"),
} }
), ),
'type': forms.Select(attrs={'class': 'form-control'}), "type": forms.Select(attrs={"class": "form-control"}),
'score_type': forms.Select(attrs={'class': 'form-control'}), "score_type": forms.Select(attrs={"class": "form-control"}),
'score': forms.TextInput( "score": forms.TextInput(
attrs={'class': 'form-control', 'placeholder': 'xx,xxx'} attrs={"class": "form-control", "placeholder": "xx,xxx"}
), ),
'tof': forms.HiddenInput(), "tof": forms.HiddenInput(),
} }
gymnast_related = forms.CharField( gymnast_related = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching gymnast…', "placeholder": "Searching gymnast…",
'data-ref': '#id_gymnast', "data-ref": "#id_gymnast",
} }
) )
) )
class LearnedSkillForm(forms.ModelForm): class LearnedSkillForm(forms.ModelForm):
class Meta: class Meta:
model = LearnedSkill model = LearnedSkill
fields = ('gymnast', 'skill', 'cando', 'date') fields = ("gymnast", "skill", "cando", "date")
widgets = { widgets = {
'gymnast': forms.HiddenInput(), "gymnast": forms.HiddenInput(),
'skill': forms.HiddenInput(), "skill": forms.HiddenInput(),
'date': forms.TextInput( "date": forms.TextInput(
attrs={ attrs={
'class': 'form-control datepicker', "class": "form-control datepicker",
'placeholder': date.today().strftime('%Y-%m-%d'), "placeholder": date.today().strftime("%Y-%m-%d"),
'value': date.today().strftime('%Y-%m-%d'), "value": date.today().strftime("%Y-%m-%d"),
} }
), ),
'cando': forms.Select(attrs={'class': 'form-control'}), "cando": forms.Select(attrs={"class": "form-control"}),
} }
gymnast_related = forms.CharField( gymnast_related = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching gymnast…', "placeholder": "Searching gymnast…",
'data-ref': '#id_gymnast', "data-ref": "#id_gymnast",
} }
) )
) )
@ -70,9 +78,9 @@ class LearnedSkillForm(forms.ModelForm):
skill_related = forms.CharField( skill_related = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching skill…', "placeholder": "Searching skill…",
'data-ref': '#id_skill', "data-ref": "#id_skill",
} }
) )
) )
@ -81,49 +89,61 @@ class LearnedSkillForm(forms.ModelForm):
class ScoreForm(forms.ModelForm): class ScoreForm(forms.ModelForm):
class Meta: class Meta:
ROUTINETYPE_CHOICE = ( ROUTINETYPE_CHOICE = (
(0, 'Routine 1'), (0, "Routine 1"),
(1, 'Routine 2'), (1, "Routine 2"),
(2, 'Final\'s routine'), (2, "Final's routine"),
) )
model = Point model = Point
fields = ( fields = (
'gymnast', "gymnast",
'event', "event",
'routine_type', "routine_type",
'point_difficulty', "point_difficulty",
'point_time_of_flight', "point_time_of_flight",
'point_execution', "point_execution",
'point_horizontal_displacement', "point_horizontal_displacement",
'penality', "penality",
'total', "total",
) )
widgets = { widgets = {
'gymnast': forms.HiddenInput(), "gymnast": forms.HiddenInput(),
'event': forms.HiddenInput(), "event": forms.HiddenInput(),
'routine_type': forms.Select(attrs={'class': 'form-control'}), "routine_type": forms.Select(attrs={"class": "form-control"}),
'point_execution': forms.NumberInput( "point_execution": forms.NumberInput(
attrs={'class': 'form-control', 'placeholder': 'xx,xx',}
),
'point_difficulty': forms.NumberInput(
attrs={'class': 'form-control', 'placeholder': 'xx,xx',}
),
'point_time_of_flight': forms.NumberInput(
attrs={'class': 'form-control', 'placeholder': 'xx,xx',}
),
'point_horizontal_displacement': forms.NumberInput(
attrs={'class': 'form-control', 'placeholder': 'x,xx',}
),
'penality': forms.NumberInput(
attrs={'class': 'form-control', 'placeholder': 'xx,xx', 'value': '0'}
),
'total': forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': '000,000', "placeholder": "xx,xx",
'readonly': 'readonly', }
'maxlength': '6', ),
"point_difficulty": forms.NumberInput(
attrs={
"class": "form-control",
"placeholder": "xx,xx",
}
),
"point_time_of_flight": forms.NumberInput(
attrs={
"class": "form-control",
"placeholder": "xx,xx",
}
),
"point_horizontal_displacement": forms.NumberInput(
attrs={
"class": "form-control",
"placeholder": "x,xx",
}
),
"penality": forms.NumberInput(
attrs={"class": "form-control", "placeholder": "xx,xx", "value": "0"}
),
"total": forms.TextInput(
attrs={
"class": "form-control",
"placeholder": "000,000",
"readonly": "readonly",
"maxlength": "6",
} }
), ),
} }
@ -131,18 +151,18 @@ class ScoreForm(forms.ModelForm):
gymnast_related = forms.CharField( gymnast_related = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching…', "placeholder": "Searching…",
'data-ref': '#id_gymnast', "data-ref": "#id_gymnast",
} }
) )
) )
event_related = forms.CharField( event_related = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching…', "placeholder": "Searching…",
'data-ref': '#id_event', "data-ref": "#id_event",
} }
) )
) )
@ -151,24 +171,24 @@ class ScoreForm(forms.ModelForm):
class AccidentForm(forms.ModelForm): class AccidentForm(forms.ModelForm):
class Meta: class Meta:
model = Accident model = Accident
fields = ('gymnast', 'date', 'nb_week_off', 'informations') fields = ("gymnast", "date", "nb_week_off", "informations")
widgets = { widgets = {
'date': forms.DateInput( "date": forms.DateInput(
attrs={ attrs={
'class': 'form-control datepicker', "class": "form-control datepicker",
'placeholder': date.today().strftime('%Y-%m-%d'), "placeholder": date.today().strftime("%Y-%m-%d"),
'value': date.today().strftime('%Y-%m-%d'), "value": date.today().strftime("%Y-%m-%d"),
} }
), ),
'gymnast': forms.HiddenInput(), "gymnast": forms.HiddenInput(),
'skill': forms.HiddenInput(), "skill": forms.HiddenInput(),
'nb_week_off': forms.NumberInput( "nb_week_off": forms.NumberInput(
attrs={'class': 'form-control', 'placeholder': 'xx'} attrs={"class": "form-control", "placeholder": "xx"}
), ),
'informations': forms.Textarea( "informations": forms.Textarea(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Informations about accident: context (why, where, …), consequencies, …', "placeholder": "Informations about accident: context (why, where, …), consequencies, …",
} }
), ),
} }
@ -176,9 +196,9 @@ class AccidentForm(forms.ModelForm):
gymnast_related = forms.CharField( gymnast_related = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching gymnast…', "placeholder": "Searching gymnast…",
'data-ref': '#id_gymnast', "data-ref": "#id_gymnast",
} }
) )
) )
@ -186,35 +206,35 @@ class AccidentForm(forms.ModelForm):
required=False, required=False,
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching skill…', "placeholder": "Searching skill…",
'data-ref': '#id_skill', "data-ref": "#id_skill",
} }
) ),
) )
class MindStateForm(forms.ModelForm): class MindStateForm(forms.ModelForm):
class Meta: class Meta:
model = MindState model = MindState
fields = ('gymnast', 'date', 'score', 'informations') fields = ("gymnast", "date", "score", "informations")
widgets = { widgets = {
'gymnast': forms.HiddenInput(), "gymnast": forms.HiddenInput(),
'date': forms.TextInput( "date": forms.TextInput(
attrs={ attrs={
'class': 'form-control datepicker', "class": "form-control datepicker",
'placeholder': date.today().strftime('%Y-%m-%d'), "placeholder": date.today().strftime("%Y-%m-%d"),
'value': date.today().strftime('%Y-%m-%d'), "value": date.today().strftime("%Y-%m-%d"),
} }
), ),
'event': forms.HiddenInput(), "event": forms.HiddenInput(),
'score': forms.NumberInput( "score": forms.NumberInput(
attrs={'class': 'form-control', 'placeholder': 'xx'} attrs={"class": "form-control", "placeholder": "xx"}
), ),
'informations': forms.Textarea( "informations": forms.Textarea(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Informations about the psychological state of mind : context (why, where, …), possible consequencies, …', "placeholder": "Informations about the psychological state of mind : context (why, where, …), possible consequencies, …",
} }
), ),
} }
@ -222,9 +242,9 @@ class MindStateForm(forms.ModelForm):
gymnast_related = forms.CharField( gymnast_related = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching gymnast…', "placeholder": "Searching gymnast…",
'data-ref': '#id_gymnast', "data-ref": "#id_gymnast",
} }
) )
) )
@ -233,46 +253,54 @@ class MindStateForm(forms.ModelForm):
required=False, required=False,
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching event…', "placeholder": "Searching event…",
'data-ref': '#id_event', "data-ref": "#id_event",
} }
) ),
) )
class GymnastHasRoutineForm(forms.ModelForm): class GymnastHasRoutineForm(forms.ModelForm):
class Meta: class Meta:
model = GymnastHasRoutine model = GymnastHasRoutine
fields = ('gymnast', 'routine', 'routine_type', 'datebegin', 'dateend') fields = ("gymnast", "routine", "routine_type", "datebegin", "dateend")
widgets = { widgets = {
'gymnast': forms.HiddenInput(), "gymnast": forms.HiddenInput(),
'routine': forms.HiddenInput(), "routine": forms.HiddenInput(),
'routine_type': forms.Select(attrs={'class': 'form-control'}), "routine_type": forms.Select(attrs={"class": "form-control"}),
'datebegin': forms.DateInput(attrs={'class': 'form-control datepicker',}), "datebegin": forms.DateInput(
'dateend': forms.DateInput(attrs={'class': 'form-control datepicker',}), attrs={
"class": "form-control datepicker",
}
),
"dateend": forms.DateInput(
attrs={
"class": "form-control datepicker",
}
),
} }
gymnast_related = forms.CharField( gymnast_related = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching gymnast…', "placeholder": "Searching gymnast…",
'data-ref': '#id_gymnast', "data-ref": "#id_gymnast",
} }
) )
) )
routine_related = forms.CharField( routine_related = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching routine…', "placeholder": "Searching routine…",
'data-ref': '#id_routine', "data-ref": "#id_routine",
} }
) )
) )
class HeightWeightForm(forms.ModelForm): class HeightWeightForm(forms.ModelForm):
""" """
Formulaire d'enregistrement d'un couple taille/poids Formulaire d'enregistrement d'un couple taille/poids
@ -280,30 +308,30 @@ class HeightWeightForm(forms.ModelForm):
class Meta: class Meta:
model = HeightWeight model = HeightWeight
fields = ('gymnast', 'date', 'height', 'weight') fields = ("gymnast", "date", "height", "weight")
widgets = { widgets = {
'gymnast': forms.HiddenInput(), "gymnast": forms.HiddenInput(),
'date': forms.TextInput( "date": forms.TextInput(
attrs={ attrs={
'class': 'form-control datepicker', "class": "form-control datepicker",
'placeholder': date.today().strftime('%Y-%m-%d'), "placeholder": date.today().strftime("%Y-%m-%d"),
'value': date.today().strftime('%Y-%m-%d'), "value": date.today().strftime("%Y-%m-%d"),
} }
), ),
'height': forms.NumberInput( "height": forms.NumberInput(
attrs={'class': 'form-control', 'placeholder': 'xxx,x'} attrs={"class": "form-control", "placeholder": "xxx,x"}
), ),
'weight': forms.NumberInput( "weight": forms.NumberInput(
attrs={'class': 'form-control', 'placeholder': 'xxx,x'} attrs={"class": "form-control", "placeholder": "xxx,x"}
), ),
} }
gymnast_related = forms.CharField( gymnast_related = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching gymnast…', "placeholder": "Searching gymnast…",
'data-ref': '#id_gymnast', "data-ref": "#id_gymnast",
} }
) )
) )

View File

@ -10,111 +10,360 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('planning', '0001_initial'), ("planning", "0001_initial"),
('people', '0001_initial'), ("people", "0001_initial"),
('objective', '0001_initial'), ("objective", "0001_initial"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Point', name="Point",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('routine_type', models.PositiveSmallIntegerField(choices=[(0, 'Routine 1'), (1, 'Routine 2'), (2, 'Final')])), "id",
('point_execution', models.DecimalField(decimal_places=3, max_digits=5)), models.BigAutoField(
('point_difficulty', models.DecimalField(decimal_places=1, max_digits=3)), auto_created=True,
('point_time_of_flight', models.DecimalField(decimal_places=3, max_digits=5)), primary_key=True,
('point_horizontal_displacement', models.DecimalField(decimal_places=3, max_digits=4)), serialize=False,
('penality', models.DecimalField(decimal_places=1, max_digits=3)), verbose_name="ID",
('total', models.DecimalField(decimal_places=3, max_digits=6)), ),
('created_at', models.DateTimeField(auto_now_add=True)), ),
('updated_at', models.DateTimeField(auto_now=True)), (
('event', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='planning.event')), "routine_type",
('gymnast', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='points', to='people.gymnast')), models.PositiveSmallIntegerField(
choices=[(0, "Routine 1"), (1, "Routine 2"), (2, "Final")]
),
),
(
"point_execution",
models.DecimalField(decimal_places=3, max_digits=5),
),
(
"point_difficulty",
models.DecimalField(decimal_places=1, max_digits=3),
),
(
"point_time_of_flight",
models.DecimalField(decimal_places=3, max_digits=5),
),
(
"point_horizontal_displacement",
models.DecimalField(decimal_places=3, max_digits=4),
),
("penality", models.DecimalField(decimal_places=1, max_digits=3)),
("total", models.DecimalField(decimal_places=3, max_digits=6)),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"event",
models.ForeignKey(
default=None,
on_delete=django.db.models.deletion.CASCADE,
to="planning.event",
),
),
(
"gymnast",
models.ForeignKey(
default=None,
on_delete=django.db.models.deletion.CASCADE,
related_name="points",
to="people.gymnast",
),
),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='MindState', name="MindState",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('informations', models.TextField(blank=True, help_text='Only MarkDown is authorized', null=True, verbose_name='Comments')), "id",
('date', models.DateField(default=datetime.date.today, verbose_name='Date')), models.BigAutoField(
('score', models.PositiveSmallIntegerField(verbose_name='Score')), auto_created=True,
('created_at', models.DateTimeField(auto_now_add=True)), primary_key=True,
('updated_at', models.DateTimeField(auto_now=True)), serialize=False,
('event', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mindstate', to='planning.event')), verbose_name="ID",
('gymnast', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='mindstate', to='people.gymnast')), ),
),
(
"informations",
models.TextField(
blank=True,
help_text="Only MarkDown is authorized",
null=True,
verbose_name="Comments",
),
),
(
"date",
models.DateField(default=datetime.date.today, verbose_name="Date"),
),
("score", models.PositiveSmallIntegerField(verbose_name="Score")),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"event",
models.ForeignKey(
blank=True,
default=None,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="mindstate",
to="planning.event",
),
),
(
"gymnast",
models.ForeignKey(
default=None,
on_delete=django.db.models.deletion.CASCADE,
related_name="mindstate",
to="people.gymnast",
),
),
], ],
options={ options={
'abstract': False, "abstract": False,
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='GymnastHasRoutine', name="GymnastHasRoutine",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('routine_type', models.PositiveSmallIntegerField(choices=[(1, 'L1'), (2, 'L2'), (3, 'L3'), (4, 'L4'), (5, 'L1S'), (6, 'L2S'), (7, 'L3S'), (8, 'L4S')], default='1', verbose_name='Type')), "id",
('datebegin', models.DateField(default=datetime.date.today, verbose_name='Date begin')), models.BigAutoField(
('dateend', models.DateField(blank=True, default=datetime.date.today, null=True, verbose_name='Date end')), auto_created=True,
('gymnast', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='routines', to='people.gymnast', verbose_name='Gymnast')), primary_key=True,
('routine', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='done_by', to='objective.routine', verbose_name='Routine')), serialize=False,
verbose_name="ID",
),
),
(
"routine_type",
models.PositiveSmallIntegerField(
choices=[
(1, "L1"),
(2, "L2"),
(3, "L3"),
(4, "L4"),
(5, "L1S"),
(6, "L2S"),
(7, "L3S"),
(8, "L4S"),
],
default="1",
verbose_name="Type",
),
),
(
"datebegin",
models.DateField(
default=datetime.date.today, verbose_name="Date begin"
),
),
(
"dateend",
models.DateField(
blank=True,
default=datetime.date.today,
null=True,
verbose_name="Date end",
),
),
(
"gymnast",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="routines",
to="people.gymnast",
verbose_name="Gymnast",
),
),
(
"routine",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="done_by",
to="objective.routine",
verbose_name="Routine",
),
),
], ],
options={ options={
'verbose_name': 'Gymnast Has Routine', "verbose_name": "Gymnast Has Routine",
'verbose_name_plural': 'Gymnast Has Routines', "verbose_name_plural": "Gymnast Has Routines",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='Chrono', name="Chrono",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('type', models.PositiveSmallIntegerField(choices=[(0, '10 |'), (1, 'L1'), (2, 'L2'), (3, 'L3'), (4, 'L4'), (99, 'Other')], verbose_name='Routine type')), "id",
('score_type', models.PositiveSmallIntegerField(choices=[(0, 'Chrono'), (1, 'ToF')], verbose_name='Score type')), models.BigAutoField(
('score', models.DecimalField(decimal_places=3, max_digits=5)), auto_created=True,
('tof', models.DecimalField(blank=True, decimal_places=3, max_digits=5, null=True)), primary_key=True,
('date', models.DateField(default=datetime.date.today, verbose_name='Date')), serialize=False,
('created_at', models.DateTimeField(auto_now_add=True)), verbose_name="ID",
('updated_at', models.DateTimeField(auto_now=True)), ),
('gymnast', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chronos', to='people.gymnast', verbose_name='gymnast')), ),
(
"type",
models.PositiveSmallIntegerField(
choices=[
(0, "10 |"),
(1, "L1"),
(2, "L2"),
(3, "L3"),
(4, "L4"),
(99, "Other"),
],
verbose_name="Routine type",
),
),
(
"score_type",
models.PositiveSmallIntegerField(
choices=[(0, "Chrono"), (1, "ToF")], verbose_name="Score type"
),
),
("score", models.DecimalField(decimal_places=3, max_digits=5)),
(
"tof",
models.DecimalField(
blank=True, decimal_places=3, max_digits=5, null=True
),
),
(
"date",
models.DateField(default=datetime.date.today, verbose_name="Date"),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"gymnast",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="chronos",
to="people.gymnast",
verbose_name="gymnast",
),
),
], ],
options={ options={
'verbose_name': 'Chrono', "verbose_name": "Chrono",
'verbose_name_plural': 'Chronos', "verbose_name_plural": "Chronos",
'ordering': ['date', 'gymnast'], "ordering": ["date", "gymnast"],
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='Accident', name="Accident",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('informations', models.TextField(blank=True, help_text='Only MarkDown is authorized', null=True, verbose_name='Comments')), "id",
('date', models.DateField(verbose_name='Date')), models.BigAutoField(
('nb_week_off', models.SmallIntegerField(blank=True, null=True, verbose_name='# week off')), auto_created=True,
('created_at', models.DateTimeField(auto_now_add=True)), primary_key=True,
('updated_at', models.DateTimeField(auto_now=True)), serialize=False,
('gymnast', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='accident', to='people.gymnast', verbose_name='Gymnast')), verbose_name="ID",
('skill', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='accident', to='objective.skill', verbose_name='Skill')), ),
),
(
"informations",
models.TextField(
blank=True,
help_text="Only MarkDown is authorized",
null=True,
verbose_name="Comments",
),
),
("date", models.DateField(verbose_name="Date")),
(
"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)),
(
"gymnast",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="accident",
to="people.gymnast",
verbose_name="Gymnast",
),
),
(
"skill",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="accident",
to="objective.skill",
verbose_name="Skill",
),
),
], ],
options={ options={
'verbose_name': 'Accident', "verbose_name": "Accident",
'verbose_name_plural': 'Accidents', "verbose_name_plural": "Accidents",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='LearnedSkill', name="LearnedSkill",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('cando', models.PositiveSmallIntegerField(choices=[(0, 'No'), (1, 'With help'), (2, 'Without help'), (3, 'Chained')], verbose_name='Can do type')), "id",
('date', models.DateField(default=datetime.date.today, verbose_name='Date')), models.BigAutoField(
('created_at', models.DateTimeField(auto_now_add=True)), auto_created=True,
('updated_at', models.DateTimeField(auto_now=True)), primary_key=True,
('gymnast', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='can_do_skill', to='people.gymnast', verbose_name='gymnast')), serialize=False,
('skill', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='done_by_gymnasts', to='objective.skill', verbose_name='Skill')), verbose_name="ID",
),
),
(
"cando",
models.PositiveSmallIntegerField(
choices=[
(0, "No"),
(1, "With help"),
(2, "Without help"),
(3, "Chained"),
],
verbose_name="Can do type",
),
),
(
"date",
models.DateField(default=datetime.date.today, verbose_name="Date"),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"gymnast",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="can_do_skill",
to="people.gymnast",
verbose_name="gymnast",
),
),
(
"skill",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="done_by_gymnasts",
to="objective.skill",
verbose_name="Skill",
),
),
], ],
options={ options={
'verbose_name': 'Learned Skill', "verbose_name": "Learned Skill",
'verbose_name_plural': 'Learned Skills', "verbose_name_plural": "Learned Skills",
'unique_together': {('gymnast', 'skill', 'date')}, "unique_together": {("gymnast", "skill", "date")},
}, },
), ),
] ]

View File

@ -7,14 +7,19 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('people', '0001_initial'), ("people", "0001_initial"),
('followup', '0001_initial'), ("followup", "0001_initial"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='learnedskill', model_name="learnedskill",
name='gymnast', name="gymnast",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='known_skills', to='people.gymnast', verbose_name='gymnast'), field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="known_skills",
to="people.gymnast",
verbose_name="gymnast",
),
), ),
] ]

View File

@ -7,14 +7,19 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('objective', '0001_initial'), ("objective", "0001_initial"),
('followup', '0002_alter_learnedskill_gymnast'), ("followup", "0002_alter_learnedskill_gymnast"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='learnedskill', model_name="learnedskill",
name='skill', name="skill",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='known_by_gymnasts', to='objective.skill', verbose_name='Skill'), field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="known_by_gymnasts",
to="objective.skill",
verbose_name="Skill",
),
), ),
] ]

View File

@ -7,14 +7,19 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('objective', '0001_initial'), ("objective", "0001_initial"),
('followup', '0003_alter_learnedskill_skill'), ("followup", "0003_alter_learnedskill_skill"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='learnedskill', model_name="learnedskill",
name='skill', name="skill",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='known_by', to='objective.skill', verbose_name='Skill'), field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="known_by",
to="objective.skill",
verbose_name="Skill",
),
), ),
] ]

View File

@ -7,25 +7,49 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('objective', '0003_delete_gymnasthasroutine'), ("objective", "0003_delete_gymnasthasroutine"),
('people', '0001_initial'), ("people", "0001_initial"),
('followup', '0004_alter_learnedskill_skill'), ("followup", "0004_alter_learnedskill_skill"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='gymnasthasroutine', model_name="gymnasthasroutine",
name='gymnast', name="gymnast",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='has_routine', to='people.gymnast', verbose_name='Gymnast'), field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="has_routine",
to="people.gymnast",
verbose_name="Gymnast",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='gymnasthasroutine', model_name="gymnasthasroutine",
name='routine', name="routine",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='done_by_gymnast', to='objective.routine', verbose_name='Routine'), field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="done_by_gymnast",
to="objective.routine",
verbose_name="Routine",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='gymnasthasroutine', model_name="gymnasthasroutine",
name='routine_type', name="routine_type",
field=models.PositiveSmallIntegerField(choices=[(0, 'Other'), (1, 'L1'), (2, 'L2'), (3, 'L3'), (4, 'L4'), (5, 'L1S'), (6, 'L2S'), (7, 'L3S'), (8, 'L4S')], default='1', verbose_name='Type'), field=models.PositiveSmallIntegerField(
choices=[
(0, "Other"),
(1, "L1"),
(2, "L2"),
(3, "L3"),
(4, "L4"),
(5, "L1S"),
(6, "L2S"),
(7, "L3S"),
(8, "L4S"),
],
default="1",
verbose_name="Type",
),
), ),
] ]

View File

@ -8,40 +8,123 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('people', '0001_initial'), ("people", "0001_initial"),
('objective', '0003_delete_gymnasthasroutine'), ("objective", "0003_delete_gymnasthasroutine"),
('followup', '0005_auto_20211205_1412'), ("followup", "0005_auto_20211205_1412"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='NumberOfRoutineDone', name="NumberOfRoutineDone",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('routine_type', models.PositiveSmallIntegerField(choices=[(0, 'Other'), (1, 'L1'), (2, 'L2'), (3, 'L3'), (4, 'L4'), (5, 'L1S'), (6, 'L2S'), (7, 'L3S'), (8, 'L4S')], default='1', verbose_name='Type')), "id",
('number_of_try', models.PositiveSmallIntegerField(verbose_name='Number of try')), models.BigAutoField(
('number_of_successes', models.PositiveSmallIntegerField(verbose_name='number of successes')), auto_created=True,
('date', models.DateField(default=datetime.date.today, verbose_name='Date')), primary_key=True,
('gymnast', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='number_of_routine_done', to='people.gymnast', verbose_name='Gymnast')), serialize=False,
('routine', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='number_of_try', to='objective.routine', verbose_name='Routine')), verbose_name="ID",
),
),
(
"routine_type",
models.PositiveSmallIntegerField(
choices=[
(0, "Other"),
(1, "L1"),
(2, "L2"),
(3, "L3"),
(4, "L4"),
(5, "L1S"),
(6, "L2S"),
(7, "L3S"),
(8, "L4S"),
],
default="1",
verbose_name="Type",
),
),
(
"number_of_try",
models.PositiveSmallIntegerField(verbose_name="Number of try"),
),
(
"number_of_successes",
models.PositiveSmallIntegerField(
verbose_name="number of successes"
),
),
(
"date",
models.DateField(default=datetime.date.today, verbose_name="Date"),
),
(
"gymnast",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="number_of_routine_done",
to="people.gymnast",
verbose_name="Gymnast",
),
),
(
"routine",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="number_of_try",
to="objective.routine",
verbose_name="Routine",
),
),
], ],
options={ options={
'verbose_name': 'Number of routine done', "verbose_name": "Number of routine done",
'verbose_name_plural': 'Number of routines done', "verbose_name_plural": "Number of routines done",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='HeightWeight', name="HeightWeight",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('height', models.DecimalField(decimal_places=1, max_digits=4, verbose_name='Height')), "id",
('weight', models.DecimalField(decimal_places=1, max_digits=4, verbose_name='Weight')), models.BigAutoField(
('date', models.DateField(default=datetime.date.today, verbose_name='Date')), auto_created=True,
('gymnast', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='height_weight', to='people.gymnast', verbose_name='Gymnast')), primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"height",
models.DecimalField(
decimal_places=1, max_digits=4, verbose_name="Height"
),
),
(
"weight",
models.DecimalField(
decimal_places=1, max_digits=4, verbose_name="Weight"
),
),
(
"date",
models.DateField(default=datetime.date.today, verbose_name="Date"),
),
(
"gymnast",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="height_weight",
to="people.gymnast",
verbose_name="Gymnast",
),
),
], ],
options={ options={
'verbose_name': 'Height & weight', "verbose_name": "Height & weight",
'verbose_name_plural': 'Heights & weights', "verbose_name_plural": "Heights & weights",
}, },
), ),
] ]

View File

@ -7,20 +7,35 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('objective', '0003_delete_gymnasthasroutine'), ("objective", "0003_delete_gymnasthasroutine"),
('planning', '0001_initial'), ("planning", "0001_initial"),
('followup', '0006_heightweight_numberofroutinedone'), ("followup", "0006_heightweight_numberofroutinedone"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='accident', model_name="accident",
name='skill', name="skill",
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='accident', to='objective.skill', verbose_name='Skill'), field=models.ForeignKey(
blank=True,
default=None,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="accident",
to="objective.skill",
verbose_name="Skill",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='mindstate', model_name="mindstate",
name='event', name="event",
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mindstate', to='planning.event'), field=models.ForeignKey(
blank=True,
default=None,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="mindstate",
to="planning.event",
),
), ),
] ]

View File

@ -6,14 +6,14 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('people', '0001_initial'), ("people", "0001_initial"),
('objective', '0003_delete_gymnasthasroutine'), ("objective", "0003_delete_gymnasthasroutine"),
('followup', '0007_auto_20211213_1445'), ("followup", "0007_auto_20211213_1445"),
] ]
operations = [ operations = [
migrations.AlterUniqueTogether( migrations.AlterUniqueTogether(
name='learnedskill', name="learnedskill",
unique_together={('gymnast', 'skill', 'date', 'cando')}, unique_together={("gymnast", "skill", "date", "cando")},
), ),
] ]

View File

@ -19,6 +19,7 @@ ROUTINE_CHOICE = (
(8, "L4S"), (8, "L4S"),
) )
class Chrono(models.Model): class Chrono(models.Model):
""" """
Représente les chronos (de chandelles ou de série) enregistrés pour un(e) gymnaste. Représente les chronos (de chandelles ou de série) enregistrés pour un(e) gymnaste.
@ -71,14 +72,13 @@ class Accident(Markdownizable):
""" """
La classe `Accident` permet d'indiquer qu'un gymnaste a eu un accident, en liaison avec un La classe `Accident` permet d'indiquer qu'un gymnaste a eu un accident, en liaison avec un
skill ou non. skill ou non.
""" """
class Meta: class Meta:
verbose_name = "Accident" verbose_name = "Accident"
verbose_name_plural = "Accidents" verbose_name_plural = "Accidents"
# unique_together = ("gymnast", "skill", "date") # unique_together = ("gymnast", "skill", "date")
gymnast = models.ForeignKey( gymnast = models.ForeignKey(
Gymnast, Gymnast,
verbose_name="Gymnast", verbose_name="Gymnast",
@ -92,10 +92,12 @@ class Accident(Markdownizable):
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
default=None, default=None,
blank=True, blank=True,
null=True null=True,
) )
date = models.DateField(verbose_name="Date") date = models.DateField(verbose_name="Date")
nb_week_off = models.SmallIntegerField(blank=True, null=True, verbose_name="# week off") nb_week_off = models.SmallIntegerField(
blank=True, null=True, verbose_name="# week off"
)
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
@ -114,21 +116,20 @@ class LearnedSkill(models.Model):
TYPE_CHOICES = ((0, "No"), (1, "With help"), (2, "Without help"), (3, "Chained")) TYPE_CHOICES = ((0, "No"), (1, "With help"), (2, "Without help"), (3, "Chained"))
class Meta: class Meta:
verbose_name = 'Learned Skill' verbose_name = "Learned Skill"
verbose_name_plural = 'Learned Skills' verbose_name_plural = "Learned Skills"
unique_together = ('gymnast', 'skill', 'date', 'cando') unique_together = ("gymnast", "skill", "date", "cando")
gymnast = models.ForeignKey( gymnast = models.ForeignKey(
Gymnast, Gymnast,
verbose_name='gymnast', verbose_name="gymnast",
related_name='known_skills', related_name="known_skills",
on_delete=models.CASCADE, on_delete=models.CASCADE,
) )
skill = models.ForeignKey( skill = models.ForeignKey(
Skill, Skill,
verbose_name='Skill', verbose_name="Skill",
related_name='known_by', related_name="known_by",
on_delete=models.CASCADE, on_delete=models.CASCADE,
) )
cando = models.PositiveSmallIntegerField( cando = models.PositiveSmallIntegerField(
@ -146,11 +147,13 @@ class Point(models.Model):
ROUTINETYPE_CHOICE = ((0, "Routine 1"), (1, "Routine 2"), (2, "Final")) ROUTINETYPE_CHOICE = ((0, "Routine 1"), (1, "Routine 2"), (2, "Final"))
gymnast = models.ForeignKey(Gymnast, on_delete=models.CASCADE, default=None, related_name="points") gymnast = models.ForeignKey(
Gymnast, on_delete=models.CASCADE, default=None, related_name="points"
)
event = models.ForeignKey(Event, on_delete=models.CASCADE, default=None) event = models.ForeignKey(Event, on_delete=models.CASCADE, default=None)
routine_type = models.PositiveSmallIntegerField(choices=ROUTINETYPE_CHOICE) routine_type = models.PositiveSmallIntegerField(choices=ROUTINETYPE_CHOICE)
point_execution = models.DecimalField(max_digits=5, decimal_places=3) point_execution = models.DecimalField(max_digits=5, decimal_places=3)
point_difficulty = (models.DecimalField(max_digits=3, decimal_places=1)) point_difficulty = models.DecimalField(max_digits=3, decimal_places=1)
point_time_of_flight = models.DecimalField(max_digits=5, decimal_places=3) point_time_of_flight = models.DecimalField(max_digits=5, decimal_places=3)
point_horizontal_displacement = models.DecimalField(max_digits=4, decimal_places=3) point_horizontal_displacement = models.DecimalField(max_digits=4, decimal_places=3)
penality = models.DecimalField(max_digits=3, decimal_places=1) penality = models.DecimalField(max_digits=3, decimal_places=1)
@ -170,21 +173,30 @@ class MindState(Markdownizable):
Représente l'état d'esprit psychologique d'un gymnaste Représente l'état d'esprit psychologique d'un gymnaste
""" """
gymnast = models.ForeignKey(Gymnast, on_delete=models.CASCADE, default=None, related_name="mindstate") gymnast = models.ForeignKey(
Gymnast, on_delete=models.CASCADE, default=None, related_name="mindstate"
)
date = models.DateField(default=date.today, verbose_name="Date") date = models.DateField(default=date.today, verbose_name="Date")
event = models.ForeignKey(Event, on_delete=models.SET_NULL, default=None, blank=True, null=True, related_name="mindstate") event = models.ForeignKey(
Event,
on_delete=models.SET_NULL,
default=None,
blank=True,
null=True,
related_name="mindstate",
)
score = models.PositiveSmallIntegerField(verbose_name="Score") score = models.PositiveSmallIntegerField(verbose_name="Score")
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
def __str__(self): def __str__(self):
return '%s - %s : %s' % (self.gymnast, self.date, self.score) return "%s - %s : %s" % (self.gymnast, self.date, self.score)
class GymnastHasRoutine(models.Model): class GymnastHasRoutine(models.Model):
""" """
Classe représentant le lien entre les gymnastes et leurs séries. Classe représentant le lien entre les gymnastes et leurs séries.
""" """
class Meta: class Meta:
verbose_name = "Gymnast Has Routine" verbose_name = "Gymnast Has Routine"
@ -241,11 +253,19 @@ class NumberOfRoutineDone(models.Model):
choices=ROUTINE_CHOICE, verbose_name="Type", default="1" choices=ROUTINE_CHOICE, verbose_name="Type", default="1"
) )
number_of_try = models.PositiveSmallIntegerField(verbose_name="Number of try") number_of_try = models.PositiveSmallIntegerField(verbose_name="Number of try")
number_of_successes = models.PositiveSmallIntegerField(verbose_name="number of successes") number_of_successes = models.PositiveSmallIntegerField(
verbose_name="number of successes"
)
date = models.DateField(default=date.today, verbose_name="Date") date = models.DateField(default=date.today, verbose_name="Date")
def __str__(self): def __str__(self):
return "%s - %s (%s) : %s | %s" % (self.gymnast, self.routine_type, self.routine, self.number_of_try, self.number_of_successes) return "%s - %s (%s) : %s | %s" % (
self.gymnast,
self.routine_type,
self.routine,
self.number_of_try,
self.number_of_successes,
)
class HeightWeight(models.Model): class HeightWeight(models.Model):

View File

@ -6,16 +6,24 @@ from . import views
# Chronos # Chronos
chrono_urlpatterns = [ chrono_urlpatterns = [
path(r"", views.chrono_listing, name='chrono_list'), path(r"", views.chrono_listing, name="chrono_list"),
path(r"create/", views.chrono_create_or_update, name='chrono_create'), path(r"create/", views.chrono_create_or_update, name="chrono_create"),
path(r"create/<int:gymnastid>/", views.chrono_create_or_update, name='chrono_create_for_gymnast'), path(
r"create/<int:gymnastid>/",
views.chrono_create_or_update,
name="chrono_create_for_gymnast",
),
path(r"edit/<int:chronoid>/", views.chrono_create_or_update, name="chrono_update"), path(r"edit/<int:chronoid>/", views.chrono_create_or_update, name="chrono_update"),
] ]
# Learned Skill # Learned Skill
learnedskill_urlpatterns = [ learnedskill_urlpatterns = [
path(r"create/", views.learnedskill_create_or_update, name="learnedskill_create"), path(r"create/", views.learnedskill_create_or_update, name="learnedskill_create"),
path(r"create/<int:gymnastid>/", views.learnedskill_create_or_update, name='learnedskill_create'), path(
r"create/<int:gymnastid>/",
views.learnedskill_create_or_update,
name="learnedskill_create",
),
path(r"new/", views.gymnast_learn_skill), path(r"new/", views.gymnast_learn_skill),
] ]
@ -36,7 +44,11 @@ accident_urlpatterns = [
path(r"search/", views.accident_listing), path(r"search/", views.accident_listing),
path(r"", views.accident_listing, name="accident_list"), path(r"", views.accident_listing, name="accident_list"),
path(r"add/", views.accident_create_or_update, name="accident_create"), path(r"add/", views.accident_create_or_update, name="accident_create"),
path(r"add/<int:gymnastid>", views.accident_create_or_update, name="accident_create_for_gymnast"), path(
r"add/<int:gymnastid>",
views.accident_create_or_update,
name="accident_create_for_gymnast",
),
path( path(
r"edit/<int:accidentid>/", r"edit/<int:accidentid>/",
views.accident_create_or_update, views.accident_create_or_update,
@ -48,9 +60,17 @@ accident_urlpatterns = [
# Minstate # Minstate
mindstate_urlpatterns = [ mindstate_urlpatterns = [
path(r"", views.mindstate_listing, name="mindstate_list"), path(r"", views.mindstate_listing, name="mindstate_list"),
path(r"gymnast/<int:gymnastid>/", views.mindstate_listing, name="gymnast_mindstate_list"), path(
r"gymnast/<int:gymnastid>/",
views.mindstate_listing,
name="gymnast_mindstate_list",
),
path(r"add/", views.mindstate_create_or_update, name="mindstate_create"), path(r"add/", views.mindstate_create_or_update, name="mindstate_create"),
path(r"add/<int:gymnastid>", views.mindstate_create_or_update, name="mindstate_create_for_gymnast"), path(
r"add/<int:gymnastid>",
views.mindstate_create_or_update,
name="mindstate_create_for_gymnast",
),
path( path(
r"edit/<int:mindstateid>/", r"edit/<int:mindstateid>/",
views.mindstate_create_or_update, views.mindstate_create_or_update,
@ -62,10 +82,14 @@ mindstate_urlpatterns = [
# Height & Weight # Height & Weight
heightweight_urlpatterns = [ heightweight_urlpatterns = [
path(r"add/", views.heightweight_create_or_update, name="heightweight_create"), path(r"add/", views.heightweight_create_or_update, name="heightweight_create"),
path(r"add/<int:gymnastid>", views.heightweight_create_or_update, name="heightweight_create_for_gymnast"), path(
r"add/<int:gymnastid>",
views.heightweight_create_or_update,
name="heightweight_create_for_gymnast",
),
path( path(
r"edit/<int:heightweightid>/", r"edit/<int:heightweightid>/",
views.heightweight_create_or_update, views.heightweight_create_or_update,
name="heightweight_update", name="heightweight_update",
), ),
] ]

View File

@ -8,25 +8,33 @@ from ultron.people.models import Gymnast
from ultron.planning.models import Event from ultron.planning.models import Event
from ultron.objective.models import Skill from ultron.objective.models import Skill
from .models import Chrono, MindState, Point, Accident, LearnedSkill, HeightWeight from .models import Chrono, MindState, Point, Accident, LearnedSkill, HeightWeight
from .forms import ChronoForm, LearnedSkillForm, ScoreForm, AccidentForm, MindStateForm, HeightWeightForm from .forms import (
ChronoForm,
LearnedSkillForm,
ScoreForm,
AccidentForm,
MindStateForm,
HeightWeightForm,
)
from datetime import datetime from datetime import datetime
import simplejson import simplejson
@login_required @login_required
@require_http_methods(["GET"]) @require_http_methods(["GET"])
def chrono_listing(request): def chrono_listing(request):
""" Récupère la liste des chronos """ """Récupère la liste des chronos"""
chrono_list = Chrono.objects.all() chrono_list = Chrono.objects.all()
context = {'chrono_list': chrono_list} context = {"chrono_list": chrono_list}
return render(request, "followup/chronos/list.html", context) return render(request, "followup/chronos/list.html", context)
@login_required @login_required
@require_http_methods(["GET", "POST"]) @require_http_methods(["GET", "POST"])
def chrono_create_or_update(request, chronoid=None, gymnastid=None): def chrono_create_or_update(request, chronoid=None, gymnastid=None):
""" Création ou modification d'un chrono """ """Création ou modification d'un chrono"""
if chronoid: if chronoid:
chrono = get_object_or_404(Chrono, pk=chronoid) chrono = get_object_or_404(Chrono, pk=chronoid)
@ -47,12 +55,14 @@ def chrono_create_or_update(request, chronoid=None, gymnastid=None):
if new_chrono.score_type == 1: if new_chrono.score_type == 1:
new_chrono.tof = new_chrono.score new_chrono.tof = new_chrono.score
else: else:
tof = round(( new_chrono.score * 13 ) / 15, 3) * 1000 tof = round((new_chrono.score * 13) / 15, 3) * 1000
tof = tof - (tof % 5) tof = tof - (tof % 5)
new_chrono.tof = tof / 1000 new_chrono.tof = tof / 1000
new_chrono.save() new_chrono.save()
return HttpResponseRedirect("/gymnast/details/" + str(new_chrono.gymnast.id) + "/") return HttpResponseRedirect(
"/gymnast/details/" + str(new_chrono.gymnast.id) + "/"
)
else: else:
if data is None and gymnastid is not None: if data is None and gymnastid is not None:
@ -80,7 +90,9 @@ def gymnast_learn_skill(request):
if gymnastid and skillid: if gymnastid and skillid:
gymnast = Gymnast.objects.get(pk=gymnastid) gymnast = Gymnast.objects.get(pk=gymnastid)
skill = Skill.objects.get(pk=skillid) skill = Skill.objects.get(pk=skillid)
ls = LearnedSkill(gymnast=gymnast, skill=skill, cando=cando, date=datetime.now()) ls = LearnedSkill(
gymnast=gymnast, skill=skill, cando=cando, date=datetime.now()
)
ls.save() ls.save()
return HttpResponse(status=200) return HttpResponse(status=200)
else: else:
@ -109,7 +121,9 @@ def learnedskill_create_or_update(request, gymnastid=None):
if learnedskill_form.is_valid(): if learnedskill_form.is_valid():
learnedskill_form.save() learnedskill_form.save()
return HttpResponseRedirect("/gymnast/details/" + str(learnedskill_form.cleaned_data['gymnast'].id)) return HttpResponseRedirect(
"/gymnast/details/" + str(learnedskill_form.cleaned_data["gymnast"].id)
)
else: else:
print(learnedskill_form.errors) print(learnedskill_form.errors)
@ -148,7 +162,9 @@ def score_create_or_update(request, scoreid=None, gymnastid=None):
form.save() form.save()
return HttpResponseRedirect( return HttpResponseRedirect(
# "/gymnast/" + str(form.cleaned_data["gymnast"].id) + "/tab/scores/" # "/gymnast/" + str(form.cleaned_data["gymnast"].id) + "/tab/scores/"
"/gymnast/details/" + str(form.cleaned_data["gymnast"].id) + "/" "/gymnast/details/"
+ str(form.cleaned_data["gymnast"].id)
+ "/"
) )
# return HttpResponseRedirect("/score/") # return HttpResponseRedirect("/score/")
else: else:
@ -274,21 +290,18 @@ def mindstate_create_or_update(request, mindstateid=None, gymnastid=None, eventi
if mindstateid: if mindstateid:
mindstate = get_object_or_404(MindState, pk=mindstateid) mindstate = get_object_or_404(MindState, pk=mindstateid)
data = { data = {"gymnast_related": mindstate.gymnast, "event_related": mindstate.event}
"gymnast_related": mindstate.gymnast,
"event_related": mindstate.event
}
else: else:
mindstate = None mindstate = None
data = {} data = {}
if gymnastid is not None: if gymnastid is not None:
gymnast = get_object_or_404(Gymnast, pk=gymnastid) gymnast = get_object_or_404(Gymnast, pk=gymnastid)
data['gymnast'] = gymnastid data["gymnast"] = gymnastid
data['gymnast_related'] = str(gymnast) data["gymnast_related"] = str(gymnast)
if eventid is not None: if eventid is not None:
event = get_object_or_404(Event, pk=eventid) event = get_object_or_404(Event, pk=eventid)
data['event'] = eventid data["event"] = eventid
data['event_related'] = str(event) data["event_related"] = str(event)
if request.method == "POST": if request.method == "POST":
form = MindStateForm(request.POST, instance=mindstate) form = MindStateForm(request.POST, instance=mindstate)
@ -327,27 +340,27 @@ def heightweight_create_or_update(request, heightweightid=None, gymnastid=None):
if heightweightid: if heightweightid:
heightweight = get_object_or_404(HeightWeight, pk=heightweightid) heightweight = get_object_or_404(HeightWeight, pk=heightweightid)
data = { data = {"gymnast_related": heightweight.gymnast}
"gymnast_related": heightweight.gymnast
}
else: else:
mindstate = None mindstate = None
data = {} data = {}
if gymnastid: if gymnastid:
gymnast = get_object_or_404(Gymnast, pk=gymnastid) gymnast = get_object_or_404(Gymnast, pk=gymnastid)
data['gymnast'] = gymnastid data["gymnast"] = gymnastid
data['gymnast_related'] = str(gymnast) data["gymnast_related"] = str(gymnast)
if request.method == "POST": if request.method == "POST":
height_weight_form = HeightWeightForm(request.POST, instance=heightweight) height_weight_form = HeightWeightForm(request.POST, instance=heightweight)
if height_weight_form.is_valid(): if height_weight_form.is_valid():
height_weight_form.save() height_weight_form.save()
return HttpResponseRedirect("/gymnast/details/" + str(height_weight_form.cleaned_data['gymnast'].id)) return HttpResponseRedirect(
"/gymnast/details/" + str(height_weight_form.cleaned_data["gymnast"].id)
)
else: else:
print(height_weight_form.errors) print(height_weight_form.errors)
form = HeightWeightForm(instance=heightweight, initial=data) form = HeightWeightForm(instance=heightweight, initial=data)
context = {"form": form, "gymnastid": gymnastid, "heightweightid": heightweightid} context = {"form": form, "gymnastid": gymnastid, "heightweightid": heightweightid}
return render(request, "followup/heightweight/create.html", context) return render(request, "followup/heightweight/create.html", context)

View File

@ -5,29 +5,29 @@ from .models import Place, Club, Country
class CountryAdmin(admin.ModelAdmin): class CountryAdmin(admin.ModelAdmin):
model = Country model = Country
list_display = ('name', 'iso3', 'iso2') list_display = ("name", "iso3", "iso2")
ordering = ('name',) ordering = ("name",)
search_fields = ('name', 'nationality') search_fields = ("name", "nationality")
class ClubAdmin(admin.ModelAdmin): class ClubAdmin(admin.ModelAdmin):
model = Club model = Club
list_display = ('name', 'acronym', 'place', 'active') list_display = ("name", "acronym", "place", "active")
ordering = ('name',) ordering = ("name",)
list_filter = ('active',) list_filter = ("active",)
search_fields = ('name',) search_fields = ("name",)
autocomplete_fields = ('place',) autocomplete_fields = ("place",)
class PlaceAdmin(admin.ModelAdmin): class PlaceAdmin(admin.ModelAdmin):
model = Place model = Place
list_display = ('name', 'address', 'postal', 'city', 'active') list_display = ("name", "address", "postal", "city", "active")
ordering = ('name',) ordering = ("name",)
list_filter = ('active',) list_filter = ("active",)
search_fields = ('name', 'address', 'postal', 'city') search_fields = ("name", "address", "postal", "city")
autocomplete_fields = ('country',) autocomplete_fields = ("country",)
admin.site.register(Place, PlaceAdmin) admin.site.register(Place, PlaceAdmin)

View File

@ -2,5 +2,5 @@ from django.apps import AppConfig
class LocationConfig(AppConfig): class LocationConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField' default_auto_field = "django.db.models.BigAutoField"
name = 'ultron.location' name = "ultron.location"

View File

@ -8,53 +8,95 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = []
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Country', name="Country",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=255, verbose_name='English name')), "id",
('nationality', models.CharField(max_length=255, verbose_name='Nationality')), models.BigAutoField(
('iso2', models.CharField(max_length=2)), auto_created=True,
('iso3', models.CharField(max_length=3)), primary_key=True,
('isonum', models.PositiveSmallIntegerField()), serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=255, verbose_name="English name")),
(
"nationality",
models.CharField(max_length=255, verbose_name="Nationality"),
),
("iso2", models.CharField(max_length=2)),
("iso3", models.CharField(max_length=3)),
("isonum", models.PositiveSmallIntegerField()),
], ],
options={ options={
'verbose_name': 'Country', "verbose_name": "Country",
'verbose_name_plural': 'Countries', "verbose_name_plural": "Countries",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='Place', name="Place",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=255, verbose_name='Name')), "id",
('address', models.CharField(max_length=255, verbose_name='Address')), models.BigAutoField(
('postal', models.PositiveIntegerField(verbose_name='Postal code')), auto_created=True,
('city', models.CharField(max_length=255, verbose_name='City')), primary_key=True,
('active', models.BooleanField(default=1, verbose_name='Active')), serialize=False,
('country', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='location.country', verbose_name='Country')), verbose_name="ID",
),
),
("name", models.CharField(max_length=255, verbose_name="Name")),
("address", models.CharField(max_length=255, verbose_name="Address")),
("postal", models.PositiveIntegerField(verbose_name="Postal code")),
("city", models.CharField(max_length=255, verbose_name="City")),
("active", models.BooleanField(default=1, verbose_name="Active")),
(
"country",
models.ForeignKey(
default=None,
on_delete=django.db.models.deletion.CASCADE,
to="location.country",
verbose_name="Country",
),
),
], ],
options={ options={
'verbose_name': 'Place', "verbose_name": "Place",
'verbose_name_plural': 'Places', "verbose_name_plural": "Places",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='Club', name="Club",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=255, verbose_name='Name')), "id",
('acronym', models.CharField(max_length=4, verbose_name='Acronym')), models.BigAutoField(
('active', models.BooleanField(default=1, verbose_name='Active')), auto_created=True,
('place', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='location.place', verbose_name='Place')), primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=255, verbose_name="Name")),
("acronym", models.CharField(max_length=4, verbose_name="Acronym")),
("active", models.BooleanField(default=1, verbose_name="Active")),
(
"place",
models.ForeignKey(
default=None,
on_delete=django.db.models.deletion.CASCADE,
to="location.place",
verbose_name="Place",
),
),
], ],
options={ options={
'verbose_name': 'Club', "verbose_name": "Club",
'verbose_name_plural': 'Clubs', "verbose_name_plural": "Clubs",
}, },
), ),
] ]

View File

@ -18,5 +18,5 @@ country_urlpatterns = [
club_urlpatterns = [ club_urlpatterns = [
path(r"", views.club_listing, name="club_list"), path(r"", views.club_listing, name="club_list"),
path(r"lookup/", views.club_lookup), path(r"lookup/", views.club_lookup),
] ]

View File

@ -1,5 +1,3 @@
from datetime import datetime, timedelta, date from datetime import datetime, timedelta, date
from functools import reduce from functools import reduce
import operator import operator
@ -64,8 +62,7 @@ def country_lookup(request):
if pattern is not None and len(pattern) >= 3: if pattern is not None and len(pattern) >= 3:
results = Country.objects.filter( results = Country.objects.filter(
Q(name__icontains=pattern) Q(name__icontains=pattern) | Q(nationality__icontains=pattern)
| Q(nationality__icontains=pattern)
) )
country_list = [{"id": x.id, "Label": str(x)} for x in results] country_list = [{"id": x.id, "Label": str(x)} for x in results]
@ -126,8 +123,7 @@ def place_details(request, placeid):
@login_required @login_required
@require_http_methods(["GET"]) @require_http_methods(["GET"])
def club_listing(request): def club_listing(request):
"""Liste tous les clubs connus """Liste tous les clubs connus"""
"""
club_list = Club.objects.all() club_list = Club.objects.all()
context = {"club_list": club_list} context = {"club_list": club_list}
return render(request, "locations/clubs/list.html", context) return render(request, "locations/clubs/list.html", context)
@ -162,6 +158,7 @@ def chooseStatistics(request):
""" """
pass pass
# year = int(request.GET.get("year", date.today().year)) # year = int(request.GET.get("year", date.today().year))
# clubid = request.GET.get("clubid", None) # clubid = request.GET.get("clubid", None)
@ -188,6 +185,8 @@ def club_statistics(request, clubid):
.. todo:: tenir compte de la saison. .. todo:: tenir compte de la saison.
""" """
pass pass
# courses = Course.objects.filter(club__in=clubid).order_by( # courses = Course.objects.filter(club__in=clubid).order_by(
# "iso_day_number", "hour_begin" # "iso_day_number", "hour_begin"
# ) # )

View File

@ -1,24 +1,16 @@
from django.contrib import admin from django.contrib import admin
from .models import ( from .models import Educative, TouchPosition, Skill, Routine, RoutineSkill, Plan
Educative,
TouchPosition,
Skill,
Routine,
RoutineSkill,
Plan
)
from django_extensions.admin import ForeignKeyAutocompleteAdmin from django_extensions.admin import ForeignKeyAutocompleteAdmin
class TouchPositionAdmin(admin.ModelAdmin): class TouchPositionAdmin(admin.ModelAdmin):
model = TouchPosition model = TouchPosition
list_display = ('long_label', 'short_label', 'allowed_in_competition', 'is_default') list_display = ("long_label", "short_label", "allowed_in_competition", "is_default")
ordering = ('long_label', 'short_label') ordering = ("long_label", "short_label")
search_fields = ('long_label', 'short_label') search_fields = ("long_label", "short_label")
list_filter = ('allowed_in_competition',) list_filter = ("allowed_in_competition",)
def duplicate_skill(self, SkillAdmin, request, queryset): def duplicate_skill(self, SkillAdmin, request, queryset):
@ -31,61 +23,61 @@ class SkillAdmin(ForeignKeyAutocompleteAdmin):
model = Skill model = Skill
fields = ( fields = (
'long_label', "long_label",
'short_label', "short_label",
'informations', "informations",
'departure', "departure",
'landing', "landing",
'rotation_type', "rotation_type",
'position', "position",
'rotation', "rotation",
'twist', "twist",
'difficulty', "difficulty",
'level', "level",
'rank', "rank",
'notation', "notation",
'simplified_notation', "simplified_notation",
'is_competitive', "is_competitive",
'age_boy', "age_boy",
'age_girl', "age_girl",
'prerequisites', "prerequisites",
'educatives', "educatives",
) )
list_display = ( list_display = (
'long_label', "long_label",
'difficulty', "difficulty",
'is_competitive', "is_competitive",
'level', "level",
'rank', "rank",
'notation', "notation",
'age_boy', "age_boy",
'age_girl', "age_girl",
) )
ordering = ('long_label', 'short_label') ordering = ("long_label", "short_label")
search_fields = ('rank', 'long_label', 'short_label') search_fields = ("rank", "long_label", "short_label")
list_filter = ( list_filter = (
'is_competitive', "is_competitive",
'departure', "departure",
'landing', "landing",
'rotation_type', "rotation_type",
'rank', "rank",
'rotation', "rotation",
'level', "level",
'difficulty', "difficulty",
'age_boy', "age_boy",
'age_girl', "age_girl",
) )
filter_horizontal = ('educatives', 'prerequisites') filter_horizontal = ("educatives", "prerequisites")
duplicate_skill.short_description = 'Duplicate selected record' duplicate_skill.short_description = "Duplicate selected record"
class Media: class Media:
js = ( js = (
'js/core/jquery-3.6.0.min.js', "js/core/jquery-3.6.0.min.js",
'js/admin/skill.js', "js/admin/skill.js",
) )
@ -93,39 +85,39 @@ class RoutineAdmin(admin.ModelAdmin):
model = Routine model = Routine
fields = ( fields = (
'long_label', "long_label",
'short_label', "short_label",
'difficulty', "difficulty",
'level', "level",
'rank', "rank",
'educatives', "educatives",
'prerequisites', "prerequisites",
'age_boy', "age_boy",
'age_girl', "age_girl",
'active', "active",
'is_competitive', "is_competitive",
) )
list_display = ( list_display = (
'long_label', "long_label",
'short_label', "short_label",
'is_competitive', "is_competitive",
'active', "active",
'level', "level",
'rank', "rank",
'difficulty', "difficulty",
) )
list_filter = ('level', 'difficulty', 'is_competitive', 'active') list_filter = ("level", "difficulty", "is_competitive", "active")
search_fields = ( search_fields = (
'long_label', "long_label",
'short_label', "short_label",
) )
filter_horizontal = ('educatives',) filter_horizontal = ("educatives",)
class Media: class Media:
js = ( js = (
'js/core/jquery-3.6.0.min.js', "js/core/jquery-3.6.0.min.js",
'js/admin/routine.js', "js/admin/routine.js",
) )
# TODO: ne proposer QUE les SKILL comme educatif # TODO: ne proposer QUE les SKILL comme educatif
@ -138,24 +130,24 @@ class RoutineAdmin(admin.ModelAdmin):
class RoutineSkillAdmin(admin.ModelAdmin): class RoutineSkillAdmin(admin.ModelAdmin):
model = RoutineSkill model = RoutineSkill
list_display = ('routine', 'skill', 'rank') list_display = ("routine", "skill", "rank")
search_fields = ( search_fields = (
'routine__long_label', "routine__long_label",
'routine__short_label', "routine__short_label",
) )
ordering = ('routine', ) ordering = ("routine",)
class PlanAdmin(admin.ModelAdmin): class PlanAdmin(admin.ModelAdmin):
model = Plan model = Plan
list_display = ('gymnast', 'date', 'educative') list_display = ("gymnast", "date", "educative")
list_filter = ('gymnast', ) list_filter = ("gymnast",)
search_fields = ( search_fields = (
'gymnast__firstname', "gymnast__firstname",
'gymnast__lastname', "gymnast__lastname",
'educative__long_label', "educative__long_label",
'educative__short_label', "educative__short_label",
) )
@ -163,4 +155,4 @@ admin.site.register(TouchPosition, TouchPositionAdmin)
admin.site.register(Skill, SkillAdmin) admin.site.register(Skill, SkillAdmin)
admin.site.register(Routine, RoutineAdmin) admin.site.register(Routine, RoutineAdmin)
admin.site.register(RoutineSkill, RoutineSkillAdmin) admin.site.register(RoutineSkill, RoutineSkillAdmin)
admin.site.register(Plan, PlanAdmin) admin.site.register(Plan, PlanAdmin)

View File

@ -2,5 +2,5 @@ from django.apps import AppConfig
class ObjectiveConfig(AppConfig): class ObjectiveConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField' default_auto_field = "django.db.models.BigAutoField"
name = 'ultron.objective' name = "ultron.objective"

View File

@ -6,23 +6,30 @@ from .models import Routine, RoutineSkill, Plan
class RoutineForm(forms.ModelForm): class RoutineForm(forms.ModelForm):
class Meta: class Meta:
model = Routine model = Routine
fields = ('long_label', 'short_label', 'difficulty', 'level', 'active', 'informations') fields = (
"long_label",
"short_label",
"difficulty",
"level",
"active",
"informations",
)
widgets = { widgets = {
'long_label': forms.TextInput( "long_label": forms.TextInput(
attrs={'class': 'form-control', 'placeholder': 'Routine\'s long name'} attrs={"class": "form-control", "placeholder": "Routine's long name"}
), ),
'short_label': forms.TextInput( "short_label": forms.TextInput(
attrs={'class': 'form-control', 'placeholder': 'Routine\'s short name'} attrs={"class": "form-control", "placeholder": "Routine's short name"}
), ),
'informations': forms.Textarea( "informations": forms.Textarea(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Informations about the psychological state of mind : context (why, where, …), possible consequencies, …', "placeholder": "Informations about the psychological state of mind : context (why, where, …), possible consequencies, …",
} }
), ),
'difficulty': forms.HiddenInput(), "difficulty": forms.HiddenInput(),
'level': forms.HiddenInput(), "level": forms.HiddenInput(),
'active': forms.HiddenInput(), "active": forms.HiddenInput(),
} }
@ -33,15 +40,15 @@ class PlanForm(forms.ModelForm):
class Meta: class Meta:
model = Plan model = Plan
fields = ('date', 'gymnast', 'educative') fields = ("date", "gymnast", "educative")
widgets = { widgets = {
'gymnast': forms.HiddenInput(), "gymnast": forms.HiddenInput(),
'educative': forms.HiddenInput(), "educative": forms.HiddenInput(),
'date': forms.TextInput( "date": forms.TextInput(
attrs={ attrs={
'class': 'form-control datepicker', "class": "form-control datepicker",
'placeholder': date.today().strftime('%Y-%m-%d'), "placeholder": date.today().strftime("%Y-%m-%d"),
'value': date.today().strftime('%Y-%m-%d'), "value": date.today().strftime("%Y-%m-%d"),
} }
), ),
} }
@ -49,9 +56,9 @@ class PlanForm(forms.ModelForm):
gymnast_related = forms.CharField( gymnast_related = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching gymnast…', "placeholder": "Searching gymnast…",
'data-ref': '#id_gymnast', "data-ref": "#id_gymnast",
} }
) )
) )
@ -59,9 +66,9 @@ class PlanForm(forms.ModelForm):
educative_related = forms.CharField( educative_related = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching skill…', "placeholder": "Searching skill…",
'data-ref': '#id_skill', "data-ref": "#id_skill",
} }
) )
) )

View File

@ -9,94 +9,266 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = []
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Educative', name="Educative",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('informations', models.TextField(blank=True, help_text='Only MarkDown is authorized', null=True, verbose_name='Comments')), "id",
('long_label', models.CharField(max_length=255, verbose_name='Long Name')), models.BigAutoField(
('short_label', models.CharField(max_length=255, verbose_name='Short Name')), auto_created=True,
('difficulty', models.DecimalField(decimal_places=1, default=0.0, max_digits=3, verbose_name='Difficulty')), primary_key=True,
('level', models.PositiveSmallIntegerField(default=0, verbose_name='Level')), serialize=False,
('rank', models.PositiveSmallIntegerField(default=0, verbose_name='Rank')), verbose_name="ID",
('age_boy', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name="Boy's age")), ),
('age_girl', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name="Girl's age")), ),
('educatives', models.ManyToManyField(blank=True, related_name='educatives_of', to='objective.Educative')), (
('prerequisites', models.ManyToManyField(blank=True, related_name='prerequisite_of', to='objective.Educative')), "informations",
models.TextField(
blank=True,
help_text="Only MarkDown is authorized",
null=True,
verbose_name="Comments",
),
),
(
"long_label",
models.CharField(max_length=255, verbose_name="Long Name"),
),
(
"short_label",
models.CharField(max_length=255, verbose_name="Short Name"),
),
(
"difficulty",
models.DecimalField(
decimal_places=1,
default=0.0,
max_digits=3,
verbose_name="Difficulty",
),
),
(
"level",
models.PositiveSmallIntegerField(default=0, verbose_name="Level"),
),
(
"rank",
models.PositiveSmallIntegerField(default=0, verbose_name="Rank"),
),
(
"age_boy",
models.PositiveSmallIntegerField(
blank=True, null=True, verbose_name="Boy's age"
),
),
(
"age_girl",
models.PositiveSmallIntegerField(
blank=True, null=True, verbose_name="Girl's age"
),
),
(
"educatives",
models.ManyToManyField(
blank=True,
related_name="educatives_of",
to="objective.Educative",
),
),
(
"prerequisites",
models.ManyToManyField(
blank=True,
related_name="prerequisite_of",
to="objective.Educative",
),
),
], ],
options={ options={
'verbose_name': 'Educatif', "verbose_name": "Educatif",
'verbose_name_plural': 'Educatifs', "verbose_name_plural": "Educatifs",
'ordering': ['long_label', 'short_label'], "ordering": ["long_label", "short_label"],
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='TouchPosition', name="TouchPosition",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('long_label', models.CharField(max_length=30, verbose_name='Long label')), "id",
('short_label', models.CharField(max_length=15, verbose_name='Short label')), models.BigAutoField(
('allowed_in_competition', models.BooleanField(verbose_name='Allowed in competition')), auto_created=True,
('is_default', models.BooleanField(verbose_name='Défault ?')), primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"long_label",
models.CharField(max_length=30, verbose_name="Long label"),
),
(
"short_label",
models.CharField(max_length=15, verbose_name="Short label"),
),
(
"allowed_in_competition",
models.BooleanField(verbose_name="Allowed in competition"),
),
("is_default", models.BooleanField(verbose_name="Défault ?")),
], ],
options={ options={
'verbose_name': 'Landing', "verbose_name": "Landing",
'verbose_name_plural': 'Landings', "verbose_name_plural": "Landings",
'ordering': ['long_label', 'short_label', 'is_default', 'allowed_in_competition'], "ordering": [
"long_label",
"short_label",
"is_default",
"allowed_in_competition",
],
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='Routine', name="Routine",
fields=[ fields=[
('educative_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='objective.educative')), (
('active', models.BooleanField()), "educative_ptr",
('is_competitive', models.BooleanField(default=False)), models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="objective.educative",
),
),
("active", models.BooleanField()),
("is_competitive", models.BooleanField(default=False)),
], ],
options={ options={
'verbose_name': 'Routine', "verbose_name": "Routine",
'verbose_name_plural': 'Routines', "verbose_name_plural": "Routines",
}, },
bases=('objective.educative',), bases=("objective.educative",),
), ),
migrations.CreateModel( migrations.CreateModel(
name='Skill', name="Skill",
fields=[ fields=[
('educative_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='objective.educative')), (
('position', models.CharField(choices=[('0', 'None'), ('o', 'Tuck'), ('c', 'Puck'), ('<', 'Pike'), ('/', 'Straight'), ('//', 'Straddle')], max_length=2)), "educative_ptr",
('rotation_type', models.PositiveSmallIntegerField(choices=[(0, 'None'), (1, 'Frontward'), (2, 'Backward')], verbose_name='Type de rotation')), models.OneToOneField(
('rotation', models.PositiveSmallIntegerField(verbose_name='1/4 de rotation')), auto_created=True,
('twist', models.PositiveSmallIntegerField(verbose_name='1/2 Vrille')), on_delete=django.db.models.deletion.CASCADE,
('notation', models.CharField(max_length=25)), parent_link=True,
('simplified_notation', models.CharField(max_length=25, verbose_name='Notation simplifiée')), primary_key=True,
('is_competitive', models.BooleanField(default=False)), serialize=False,
('departure', models.ForeignKey(default=ultron.objective.models.get_default_position, on_delete=django.db.models.deletion.CASCADE, related_name='depart_of', to='objective.touchposition', verbose_name='Take-off position')), to="objective.educative",
('landing', models.ForeignKey(default=ultron.objective.models.get_default_position, on_delete=django.db.models.deletion.CASCADE, related_name='landing_of', to='objective.touchposition', verbose_name='Landing position')), ),
),
(
"position",
models.CharField(
choices=[
("0", "None"),
("o", "Tuck"),
("c", "Puck"),
("<", "Pike"),
("/", "Straight"),
("//", "Straddle"),
],
max_length=2,
),
),
(
"rotation_type",
models.PositiveSmallIntegerField(
choices=[(0, "None"), (1, "Frontward"), (2, "Backward")],
verbose_name="Type de rotation",
),
),
(
"rotation",
models.PositiveSmallIntegerField(verbose_name="1/4 de rotation"),
),
("twist", models.PositiveSmallIntegerField(verbose_name="1/2 Vrille")),
("notation", models.CharField(max_length=25)),
(
"simplified_notation",
models.CharField(max_length=25, verbose_name="Notation simplifiée"),
),
("is_competitive", models.BooleanField(default=False)),
(
"departure",
models.ForeignKey(
default=ultron.objective.models.get_default_position,
on_delete=django.db.models.deletion.CASCADE,
related_name="depart_of",
to="objective.touchposition",
verbose_name="Take-off position",
),
),
(
"landing",
models.ForeignKey(
default=ultron.objective.models.get_default_position,
on_delete=django.db.models.deletion.CASCADE,
related_name="landing_of",
to="objective.touchposition",
verbose_name="Landing position",
),
),
], ],
options={ options={
'verbose_name': 'Skill', "verbose_name": "Skill",
'verbose_name_plural': 'Skills', "verbose_name_plural": "Skills",
}, },
bases=('objective.educative',), bases=("objective.educative",),
), ),
migrations.CreateModel( migrations.CreateModel(
name='RoutineSkill', name="RoutineSkill",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('rank', models.PositiveSmallIntegerField()), "id",
('routine', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='skill_links', to='objective.routine')), models.BigAutoField(
('skill', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='routine_links', to='objective.skill')), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("rank", models.PositiveSmallIntegerField()),
(
"routine",
models.ForeignKey(
default=None,
on_delete=django.db.models.deletion.CASCADE,
related_name="skill_links",
to="objective.routine",
),
),
(
"skill",
models.ForeignKey(
default=None,
on_delete=django.db.models.deletion.CASCADE,
related_name="routine_links",
to="objective.skill",
),
),
], ],
options={ options={
'ordering': ('rank',), "ordering": ("rank",),
}, },
), ),
migrations.AddField( migrations.AddField(
model_name='routine', model_name="routine",
name='jumps', name="jumps",
field=models.ManyToManyField(through='objective.RoutineSkill', to='objective.Skill', verbose_name='routine'), field=models.ManyToManyField(
through="objective.RoutineSkill",
to="objective.Skill",
verbose_name="routine",
),
), ),
] ]

View File

@ -8,24 +8,78 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('people', '0001_initial'), ("people", "0001_initial"),
('objective', '0001_initial'), ("objective", "0001_initial"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='GymnastHasRoutine', name="GymnastHasRoutine",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('routine_type', models.PositiveSmallIntegerField(choices=[(0, 'Other'), (1, 'L1'), (2, 'L2'), (3, 'L3'), (4, 'L4'), (5, 'L1S'), (6, 'L2S'), (7, 'L3S'), (8, 'L4S')], default='1', verbose_name='Type')), "id",
('datebegin', models.DateField(default=datetime.date.today, verbose_name='Date begin')), models.BigAutoField(
('dateend', models.DateField(blank=True, default=datetime.date.today, null=True, verbose_name='Date end')), auto_created=True,
('gymnast', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='has_routine', to='people.gymnast', verbose_name='Gymnast')), primary_key=True,
('routine', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='used_by_gymnast', to='objective.routine', verbose_name='Routine')), serialize=False,
verbose_name="ID",
),
),
(
"routine_type",
models.PositiveSmallIntegerField(
choices=[
(0, "Other"),
(1, "L1"),
(2, "L2"),
(3, "L3"),
(4, "L4"),
(5, "L1S"),
(6, "L2S"),
(7, "L3S"),
(8, "L4S"),
],
default="1",
verbose_name="Type",
),
),
(
"datebegin",
models.DateField(
default=datetime.date.today, verbose_name="Date begin"
),
),
(
"dateend",
models.DateField(
blank=True,
default=datetime.date.today,
null=True,
verbose_name="Date end",
),
),
(
"gymnast",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="has_routine",
to="people.gymnast",
verbose_name="Gymnast",
),
),
(
"routine",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="used_by_gymnast",
to="objective.routine",
verbose_name="Routine",
),
),
], ],
options={ options={
'verbose_name': 'Gymnast Has Routine', "verbose_name": "Gymnast Has Routine",
'verbose_name_plural': 'Gymnast Has Routines', "verbose_name_plural": "Gymnast Has Routines",
}, },
), ),
] ]

View File

@ -6,11 +6,11 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('objective', '0002_gymnasthasroutine'), ("objective", "0002_gymnasthasroutine"),
] ]
operations = [ operations = [
migrations.DeleteModel( migrations.DeleteModel(
name='GymnastHasRoutine', name="GymnastHasRoutine",
), ),
] ]

View File

@ -8,24 +8,51 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('people', '0001_initial'), ("people", "0001_initial"),
('objective', '0003_delete_gymnasthasroutine'), ("objective", "0003_delete_gymnasthasroutine"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Plan', name="Plan",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('date', models.DateField(default=datetime.date.today, verbose_name='Date')), "id",
('educative', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='plan', to='objective.educative', verbose_name='Skill')), models.BigAutoField(
('gymnast', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='todo', to='people.gymnast', verbose_name='Gymnast')), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"date",
models.DateField(default=datetime.date.today, verbose_name="Date"),
),
(
"educative",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="plan",
to="objective.educative",
verbose_name="Skill",
),
),
(
"gymnast",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="todo",
to="people.gymnast",
verbose_name="Gymnast",
),
),
], ],
options={ options={
'verbose_name': 'Plan', "verbose_name": "Plan",
'verbose_name_plural': 'Plans', "verbose_name_plural": "Plans",
'ordering': ['date', 'educative', 'gymnast'], "ordering": ["date", "educative", "gymnast"],
'unique_together': {('gymnast', 'educative')}, "unique_together": {("gymnast", "educative")},
}, },
), ),
] ]

View File

@ -45,7 +45,7 @@ class Educative(Markdownizable):
class TouchPosition(models.Model): class TouchPosition(models.Model):
""" """
Classe représentant les différentes position d'arrivée/départ (landing position) en trampoline. Classe représentant les différentes position d'arrivée/départ (landing position) en trampoline.
""" """
class Meta: class Meta:
@ -274,8 +274,8 @@ class RoutineSkill(models.Model):
class Plan(models.Model): class Plan(models.Model):
""" """
Classe représentant les objectifs qu'un gymnaste devra savoir faire pour une date donnée. Classe représentant les objectifs qu'un gymnaste devra savoir faire pour une date donnée.
""" """
class Meta: class Meta:
verbose_name = "Plan" verbose_name = "Plan"
@ -284,10 +284,10 @@ class Plan(models.Model):
unique_together = ("gymnast", "educative") unique_together = ("gymnast", "educative")
gymnast = models.ForeignKey( gymnast = models.ForeignKey(
'people.Gymnast', "people.Gymnast",
verbose_name="Gymnast", verbose_name="Gymnast",
related_name="todo", related_name="todo",
on_delete=models.CASCADE on_delete=models.CASCADE,
) )
educative = models.ForeignKey( educative = models.ForeignKey(
Educative, Educative,
@ -302,4 +302,4 @@ class Plan(models.Model):
self.gymnast, self.gymnast,
self.educative.short_label, self.educative.short_label,
self.date, self.date,
) )

View File

@ -24,7 +24,6 @@ routine_urlpatterns = [
r"edit/<int:routineid>/", views.routine_create_or_update, name="routine_update" r"edit/<int:routineid>/", views.routine_create_or_update, name="routine_update"
), ),
path(r"<int:routineid>", views.routine_details, name="routine_details"), path(r"<int:routineid>", views.routine_details, name="routine_details"),
path(r"compose/<int:routineid>/", views.compose_routine, name="compose_routine"), path(r"compose/<int:routineid>/", views.compose_routine, name="compose_routine"),
path( path(
r"<int:routineid>/add_skill/<int:skillid>/order/<int:order>/", r"<int:routineid>/add_skill/<int:skillid>/order/<int:order>/",
@ -43,20 +42,16 @@ routine_urlpatterns = [
# Plan # Plan
plan_urlpatterns = [ plan_urlpatterns = [
path( path(r"add/", views.plan_create_or_update, name="plan_create"),
r"add/",
views.plan_create_or_update,
name="plan_create"
),
path( path(
r"add/<int:gymnast_id>/", r"add/<int:gymnast_id>/",
views.plan_create_or_update, views.plan_create_or_update,
name="add_plan_for_gymnast" name="add_plan_for_gymnast",
), ),
path( path(
r"add/<int:gymnast_id>/<int:skill_id>/", r"add/<int:gymnast_id>/<int:skill_id>/",
views.plan_create_or_update, views.plan_create_or_update,
name="add_skill_for_gymnast" name="add_skill_for_gymnast",
), ),
path( path(
r"edit/<int:plan_id>/", r"edit/<int:plan_id>/",

View File

@ -6,7 +6,7 @@ from django.db.models import Q
from django.urls import reverse from django.urls import reverse
from ultron.people.models import Gymnast from ultron.people.models import Gymnast
from .models import Skill, Routine, RoutineSkill from .models import Skill, Routine, RoutineSkill, Plan
from .forms import RoutineForm, PlanForm from .forms import RoutineForm, PlanForm
import simplejson import simplejson
@ -21,14 +21,16 @@ def skill_lookup(request):
""" """
results = [] results = []
pattern = request.GET.get('pattern', None) pattern = request.GET.get("pattern", None)
# Ignore queries shorter than length 2 # Ignore queries shorter than length 2
if pattern is not None and len(pattern) > 2: if pattern is not None and len(pattern) > 2:
model_results = Skill.objects.filter( model_results = Skill.objects.filter(
Q(short_label__icontains=pattern) | Q(long_label__icontains=pattern) Q(short_label__icontains=pattern) | Q(long_label__icontains=pattern)
) )
results = [{'ID': x.id, 'Name': str(x), 'Notation': x.notation} for x in model_results] results = [
{"ID": x.id, "Name": str(x), "Notation": x.notation} for x in model_results
]
json = simplejson.dumps(results) json = simplejson.dumps(results)
return HttpResponse(json, content_type="application/json") return HttpResponse(json, content_type="application/json")
@ -58,8 +60,8 @@ def skill_listing(request, field=None, expression=None, value=None, level=None):
else: else:
skill_list = Skill.objects.all() skill_list = Skill.objects.all()
context = {'skill_list': skill_list} context = {"skill_list": skill_list}
return render(request, 'objectives/skills/list.html', context) return render(request, "objectives/skills/list.html", context)
@login_required @login_required
@ -167,7 +169,10 @@ def routine_details(request, routineid):
if skill_link.skill.age_boy is not None and skill_link.skill.age_boy > age_boy: if skill_link.skill.age_boy is not None and skill_link.skill.age_boy > age_boy:
age_boy = skill_link.skill.age_boy age_boy = skill_link.skill.age_boy
if skill_link.skill.age_girl is not None and skill_link.skill.age_girl > age_girl: if (
skill_link.skill.age_girl is not None
and skill_link.skill.age_girl > age_girl
):
age_girl = skill_link.skill.age_girl age_girl = skill_link.skill.age_girl
if routine.skill_links.all().count() != 10: if routine.skill_links.all().count() != 10:
@ -198,7 +203,7 @@ def routine_details(request, routineid):
@login_required @login_required
@require_http_methods(["GET", "POST"]) @require_http_methods(["GET", "POST"])
def routine_create_or_update(request, routineid=None): def routine_create_or_update(request, routineid=None):
""" Création d'une série. """Création d'une série.
Args: Args:
routine_id (int): identifiant d'un object de classe <routine>. routine_id (int): identifiant d'un object de classe <routine>.
@ -266,7 +271,7 @@ def link_skill_to_routine(request, routineid, skillid, order):
@login_required @login_required
@require_http_methods(["GET", "POST"]) @require_http_methods(["GET", "POST"])
def plan_create_or_update(request, plan_id=None, gymnast_id=None, skill_id=None): def plan_create_or_update(request, plan_id=None, gymnast_id=None, skill_id=None):
""" Création d'un plan. """Création d'un plan.
Args: Args:
plan_id (int): identifiant d'un plan (classe <Plan>). plan_id (int): identifiant d'un plan (classe <Plan>).
@ -277,10 +282,10 @@ def plan_create_or_update(request, plan_id=None, gymnast_id=None, skill_id=None)
if plan_id: if plan_id:
plan = get_object_or_404(Plan, pk=plan_id) plan = get_object_or_404(Plan, pk=plan_id)
data = { data = {
'gymnast': plan.gymnast.id, "gymnast": plan.gymnast.id,
'gymnast_related': str(chrono.gymnast), "gymnast_related": str(plan.gymnast),
'skill': plan.skill.id, "skill": plan.skill.id,
'skill_related': str(plan.skill), "skill_related": str(plan.skill),
} }
else: else:
plan = None plan = None
@ -288,15 +293,15 @@ def plan_create_or_update(request, plan_id=None, gymnast_id=None, skill_id=None)
if gymnast_id: if gymnast_id:
gymnast = get_object_or_404(Gymnast, pk=gymnast_id) gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
data['gymnast'] = gymnast_id data["gymnast"] = gymnast_id
data['gymnast_related'] = str(gymnast) data["gymnast_related"] = str(gymnast)
if skill_id: if skill_id:
skill = get_object_or_404(Skill, pk=skill_id) skill = get_object_or_404(Skill, pk=skill_id)
data['educative'] = skill_id data["educative"] = skill_id
data['educative_related'] = str(skill) data["educative_related"] = str(skill)
if request.method == 'POST': if request.method == "POST":
form = PlanForm(request.POST, instance=plan) form = PlanForm(request.POST, instance=plan)
if form.is_valid(): if form.is_valid():
@ -307,4 +312,4 @@ def plan_create_or_update(request, plan_id=None, gymnast_id=None, skill_id=None)
form = PlanForm(instance=plan, initial=data) form = PlanForm(instance=plan, initial=data)
context = {"form": form, "plan_id": plan_id} context = {"form": form, "plan_id": plan_id}
return render(request, "objectives/plan/create.html", context) return render(request, "objectives/plan/create.html", context)

View File

@ -6,19 +6,20 @@ class GymnastAdmin(admin.ModelAdmin):
model = Gymnast model = Gymnast
fields = ( fields = (
'last_name', "last_name",
'first_name', "first_name",
'birthdate', "birthdate",
'gender', "gender",
'trainings_by_week', "trainings_by_week",
'hours_by_week', "hours_by_week",
'is_active', "is_active",
# 'club' # 'club'
) )
list_display = ('last_name', 'first_name', 'age', 'is_active') # , 'club' list_display = ("last_name", "first_name", "age", "is_active") # , 'club'
list_filter = ('gender', 'is_active') # , 'club' list_filter = ("gender", "is_active") # , 'club'
search_fields = ('last_name', 'first_name') search_fields = ("last_name", "first_name")
# autocomplete_fields = ('club',) # autocomplete_fields = ('club',)
admin.site.register(Gymnast, GymnastAdmin) admin.site.register(Gymnast, GymnastAdmin)

View File

@ -2,5 +2,5 @@ from django.apps import AppConfig
class PeopleConfig(AppConfig): class PeopleConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField' default_auto_field = "django.db.models.BigAutoField"
name = 'ultron.people' name = "ultron.people"

View File

@ -1,51 +1,48 @@
'''Formulaires de gestion des données entrantes pour les gymnastes et accidents.''' """Formulaires de gestion des données entrantes pour les gymnastes et accidents."""
from django import forms from django import forms
from .models import ( from .models import Gymnast
Gymnast
)
class GymnastForm(forms.ModelForm): class GymnastForm(forms.ModelForm):
class Meta: class Meta:
model = Gymnast model = Gymnast
fields = ( fields = (
'last_name', "last_name",
'first_name', "first_name",
'birthdate', "birthdate",
'gender', "gender",
'is_active', "is_active",
'club', "club",
'trainings_by_week', "trainings_by_week",
'hours_by_week' "hours_by_week",
) )
widgets = { widgets = {
'last_name': forms.TextInput( "last_name": forms.TextInput(
attrs={'class': 'form-control', 'placeholder': 'Lastname'} attrs={"class": "form-control", "placeholder": "Lastname"}
), ),
'first_name': forms.TextInput( "first_name": forms.TextInput(
attrs={'class': 'form-control', 'placeholder': 'Firstname'} attrs={"class": "form-control", "placeholder": "Firstname"}
), ),
'birthdate': forms.DateInput(attrs={'class': 'form-control datepicker'}), "birthdate": forms.DateInput(attrs={"class": "form-control datepicker"}),
'gender': forms.Select(attrs={'class': 'form-control'}), "gender": forms.Select(attrs={"class": "form-control"}),
'club': forms.HiddenInput(), "club": forms.HiddenInput(),
'trainings_by_week': forms.TextInput( "trainings_by_week": forms.TextInput(
attrs={'class': 'form-control', 'placeholder': '5'} attrs={"class": "form-control", "placeholder": "5"}
), ),
'hours_by_week': forms.TextInput( "hours_by_week": forms.TextInput(
attrs={'class': 'form-control', 'placeholder': '11,5'} attrs={"class": "form-control", "placeholder": "11,5"}
), ),
} }
club_related = forms.CharField( club_related = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching club…', "placeholder": "Searching club…",
'data-ref': '#id_club', "data-ref": "#id_club",
} }
) )
) )

View File

@ -9,27 +9,62 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('location', '0001_initial'), ("location", "0001_initial"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Gymnast', name="Gymnast",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('informations', models.TextField(blank=True, help_text='Only MarkDown is authorized', null=True, verbose_name='Comments')), "id",
('last_name', models.CharField(max_length=40)), models.BigAutoField(
('first_name', models.CharField(max_length=25)), auto_created=True,
('birthdate', models.DateField(verbose_name='Date de naissance')), primary_key=True,
('gender', models.PositiveSmallIntegerField(choices=[(0, 'Male'), (1, 'Female')], verbose_name='Sexe')), serialize=False,
('is_active', models.BooleanField(default=1, verbose_name='Active')), verbose_name="ID",
('trainings_by_week', models.PositiveSmallIntegerField(verbose_name='# Training by week')), ),
('hours_by_week', models.PositiveSmallIntegerField(verbose_name='# Hours by week')), ),
('club', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='gymnast', to='location.club')), (
"informations",
models.TextField(
blank=True,
help_text="Only MarkDown is authorized",
null=True,
verbose_name="Comments",
),
),
("last_name", models.CharField(max_length=40)),
("first_name", models.CharField(max_length=25)),
("birthdate", models.DateField(verbose_name="Date de naissance")),
(
"gender",
models.PositiveSmallIntegerField(
choices=[(0, "Male"), (1, "Female")], verbose_name="Sexe"
),
),
("is_active", models.BooleanField(default=1, verbose_name="Active")),
(
"trainings_by_week",
models.PositiveSmallIntegerField(verbose_name="# Training by week"),
),
(
"hours_by_week",
models.PositiveSmallIntegerField(verbose_name="# Hours by week"),
),
(
"club",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="gymnast",
to="location.club",
),
),
], ],
options={ options={
'verbose_name': 'Gymnast', "verbose_name": "Gymnast",
'verbose_name_plural': 'Gymnasts', "verbose_name_plural": "Gymnasts",
}, },
), ),
] ]

View File

@ -11,8 +11,8 @@ from ultron.tools.models import Markdownizable
class Gymnast(Markdownizable): class Gymnast(Markdownizable):
"""Représente un gymnaste. """Représente un gymnaste.
Un gymnaste peut être actif ou inactif. Un gymnaste peut être actif ou inactif.
""" """
class Meta: class Meta:
verbose_name = "Gymnast" verbose_name = "Gymnast"
@ -30,7 +30,9 @@ class Gymnast(Markdownizable):
club = models.ForeignKey( club = models.ForeignKey(
Club, null=True, on_delete=models.SET_NULL, related_name="gymnast" Club, null=True, on_delete=models.SET_NULL, related_name="gymnast"
) )
trainings_by_week = models.PositiveSmallIntegerField(verbose_name="# Training by week") trainings_by_week = models.PositiveSmallIntegerField(
verbose_name="# Training by week"
)
hours_by_week = models.PositiveSmallIntegerField(verbose_name="# Hours by week") hours_by_week = models.PositiveSmallIntegerField(verbose_name="# Hours by week")
def __str__(self): def __str__(self):
@ -40,16 +42,16 @@ class Gymnast(Markdownizable):
def next_birthday(self): def next_birthday(self):
"""Définit la prochaine date (de fête) d'anniversaire pour cette personne. """Définit la prochaine date (de fête) d'anniversaire pour cette personne.
Returns: Returns:
Soit le jour/mois pour cette année Soit le jour/mois pour cette année
Soit le jour/mois pour l'année prochaine. Soit le jour/mois pour l'année prochaine.
Examples: en supposant qu'on soit le 23/05/2019 Examples: en supposant qu'on soit le 23/05/2019
>>> from datetime import date >>> from datetime import date
>>> gregg = Gymnast(name='Tru', firstname='Gregg', birthdate=date(1982, 2, 5)) >>> gregg = Gymnast(name='Tru', firstname='Gregg', birthdate=date(1982, 2, 5))
>>> gregg.next_birthday() >>> gregg.next_birthday()
Date(2020, 2, 5) Date(2020, 2, 5)
""" """
now = pendulum.now() now = pendulum.now()
@ -68,7 +70,7 @@ class Gymnast(Markdownizable):
@property @property
def age(self): def age(self):
""" Renvoie l'âge d'un gymnaste. """ """Renvoie l'âge d'un gymnaste."""
today = date.today() today = date.today()
return ( return (
today.year today.year
@ -78,28 +80,34 @@ class Gymnast(Markdownizable):
@property @property
def next_age(self): def next_age(self):
""" Renvoie l'âge prochain du gymnaste. """ """Renvoie l'âge prochain du gymnaste."""
return (self.age) + 1 return (self.age) + 1
def min_rank_skill(self): def min_rank_skill(self):
tmp = Skill.objects.filter(known_by__gymnast=self.id).order_by("rank").values('rank')[:1] tmp = (
Skill.objects.filter(known_by__gymnast=self.id)
.order_by("rank")
.values("rank")[:1]
)
if tmp: if tmp:
min_rank = tmp[0]['rank'] min_rank = tmp[0]["rank"]
else: else:
min_rank = 0 min_rank = 0
return min_rank return min_rank
def max_rank_skill(self): def max_rank_skill(self):
tmp = Skill.objects.filter(known_by__gymnast=self.id).order_by( tmp = (
"-rank" Skill.objects.filter(known_by__gymnast=self.id)
).values('rank')[:1] .order_by("-rank")
.values("rank")[:1]
)
if tmp: if tmp:
max_rank = tmp[0]['rank'] max_rank = tmp[0]["rank"]
else: else:
max_rank = 0 max_rank = 0
return max_rank return max_rank
def known_skill_by_rank(self): def known_skill_by_rank(self):
@ -118,9 +126,13 @@ class Gymnast(Markdownizable):
""" """
Retourne le niveau maximum des skill que le gymnaste sait faire. Retourne le niveau maximum des skill que le gymnaste sait faire.
""" """
tmp = Skill.objects.filter(known_by__gymnast=self.id).order_by("-level").values('level')[:1] tmp = (
Skill.objects.filter(known_by__gymnast=self.id)
.order_by("-level")
.values("level")[:1]
)
if tmp: if tmp:
max_level = tmp[0]['level'] max_level = tmp[0]["level"]
else: else:
max_level = 0 max_level = 0
@ -143,25 +155,33 @@ class Gymnast(Markdownizable):
Renvoie la liste des skill inférieurs ou égaux au niveau max que le gymnaste ne sait *pas* faire. Renvoie la liste des skill inférieurs ou égaux au niveau max que le gymnaste ne sait *pas* faire.
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) 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)
""" """
return Skill.objects.filter(level__lte=max_level_skill).exclude(known_by__gymnast=self.id) return Skill.objects.filter(level__lte=max_level_skill).exclude(
known_by__gymnast=self.id
)
def unknown_skill_gt_level(self, max_level_skill): def unknown_skill_gt_level(self, max_level_skill):
""" """
Renvoie la liste des skill inférieurs ou égaux au niveau max que le gymnaste ne sait *pas* faire. Renvoie la liste des skill inférieurs ou égaux au niveau max que le gymnaste ne sait *pas* faire.
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) 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)
""" """
return Skill.objects.filter(level__gt=max_level_skill).exclude(known_by__gymnast=self.id) return Skill.objects.filter(level__gt=max_level_skill).exclude(
known_by__gymnast=self.id
)
def unknown_skill_lte_rank(self, max_rank_skill): def unknown_skill_lte_rank(self, max_rank_skill):
# Liste des Skill que le gymnaste ne sait PAS faire, classé par niveau # 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) # (ayant un niveau inférieur ou égal au niveau max du gym)
return Skill.objects.filter(level__lte=max_rank_skill).exclude(known_by__gymnast=self.id) return Skill.objects.filter(level__lte=max_rank_skill).exclude(
known_by__gymnast=self.id
)
def unknown_skill_gt_rank(self, max_rank_skill): def unknown_skill_gt_rank(self, max_rank_skill):
""" """
Liste des Skill que le gymnaste ne sais PAS faire (ayant un niveau plus grand que le niveau max du gym) Liste des Skill que le gymnaste ne sais PAS faire (ayant un niveau plus grand que le niveau max du gym)
""" """
return Skill.objects.filter(level__gt=max_rank_skill).exclude(known_by__gymnast=self.id) return Skill.objects.filter(level__gt=max_rank_skill).exclude(
known_by__gymnast=self.id
)
@staticmethod @staticmethod
def compute_completude(total_skill, gymnast_nb_known_skills, max_skill): def compute_completude(total_skill, gymnast_nb_known_skills, max_skill):
@ -192,7 +212,10 @@ class Gymnast(Markdownizable):
skill["nb_skill"], skill["nb_skill"],
nb_known_skill_by_level[j]["nb_known_skill"], nb_known_skill_by_level[j]["nb_known_skill"],
int( int(
(nb_known_skill_by_level[j]["nb_known_skill"] / skill["nb_skill"]) (
nb_known_skill_by_level[j]["nb_known_skill"]
/ skill["nb_skill"]
)
* 100 * 100
), ),
) )
@ -226,7 +249,10 @@ class Gymnast(Markdownizable):
skill["nb_skill"], skill["nb_skill"],
nb_known_skill_by_rank[j]["nb_known_skill"], nb_known_skill_by_rank[j]["nb_known_skill"],
int( int(
(nb_known_skill_by_rank[j]["nb_known_skill"] / skill["nb_skill"]) (
nb_known_skill_by_rank[j]["nb_known_skill"]
/ skill["nb_skill"]
)
* 100 * 100
), ),
) )
@ -263,12 +289,14 @@ class Gymnast(Markdownizable):
context = {} context = {}
max_level_skill = self.max_level_skill() max_level_skill = self.max_level_skill()
nb_known_skill_by_level = self.nb_known_skill_by_level() nb_known_skill_by_level = self.nb_known_skill_by_level()
gymnast_nb_known_skills = self.known_skills.distinct('skill').count() gymnast_nb_known_skills = self.known_skills.distinct("skill").count()
if max_level_skill > 0: if max_level_skill > 0:
nb_skill_by_level = Skill.nb_skill_by_level(max_level_skill) nb_skill_by_level = Skill.nb_skill_by_level(max_level_skill)
context["total_skill"] = Skill.nb_skill_lte_level(max_level_skill) context["total_skill"] = Skill.nb_skill_lte_level(max_level_skill)
context["percentages"] = self.compute_level_statistics(nb_skill_by_level, nb_known_skill_by_level) context["percentages"] = self.compute_level_statistics(
nb_skill_by_level, nb_known_skill_by_level
)
context["skill_by_level"] = self.unknown_skill_lte_level(max_level_skill) context["skill_by_level"] = self.unknown_skill_lte_level(max_level_skill)
context["unknown_skill"] = self.unknown_skill_gt_level(max_level_skill) context["unknown_skill"] = self.unknown_skill_gt_level(max_level_skill)
else: else:
@ -276,7 +304,9 @@ class Gymnast(Markdownizable):
context["total_skill"] = tmp.count() context["total_skill"] = tmp.count()
context["unknown_skill"] = tmp context["unknown_skill"] = tmp
context["completude"], context["evaluated_level"] = self.compute_completude(context["total_skill"], gymnast_nb_known_skills, max_level_skill) context["completude"], context["evaluated_level"] = self.compute_completude(
context["total_skill"], gymnast_nb_known_skills, max_level_skill
)
context["max_level_skill"] = max_level_skill context["max_level_skill"] = max_level_skill
return context return context
@ -291,12 +321,14 @@ class Gymnast(Markdownizable):
max_rank_skill = self.max_rank_skill() max_rank_skill = self.max_rank_skill()
context["max_rank_skill"] = max_rank_skill context["max_rank_skill"] = max_rank_skill
nb_known_skill_by_rank = self.known_skill_by_rank() nb_known_skill_by_rank = self.known_skill_by_rank()
gymnast_nb_known_skills = self.known_skills.distinct('skill').count() gymnast_nb_known_skills = self.known_skills.distinct("skill").count()
if max_rank_skill > 0: if max_rank_skill > 0:
nb_skill_by_rank = Skill.nb_skill_by_rank(max_rank_skill) nb_skill_by_rank = Skill.nb_skill_by_rank(max_rank_skill)
context["total_skill"] = Skill.nb_skill_lte_rank(max_rank_skill) context["total_skill"] = Skill.nb_skill_lte_rank(max_rank_skill)
context["percentages"] = self.compute_rank_statistics(nb_skill_by_rank, nb_known_skill_by_rank) context["percentages"] = self.compute_rank_statistics(
nb_skill_by_rank, nb_known_skill_by_rank
)
context["skill_by_rank"] = self.unknown_skill_lte_rank(max_rank_skill) context["skill_by_rank"] = self.unknown_skill_lte_rank(max_rank_skill)
context["unknown_skill"] = self.unknown_skill_gt_rank(max_rank_skill) context["unknown_skill"] = self.unknown_skill_gt_rank(max_rank_skill)
else: else:
@ -304,6 +336,8 @@ class Gymnast(Markdownizable):
context["unknown_skill"] = tmp context["unknown_skill"] = tmp
context["total_skill"] = tmp.count() context["total_skill"] = tmp.count()
context["completude"], context["evaluated_level"] = self.compute_completude(context["total_skill"], gymnast_nb_known_skills, max_rank_skill) context["completude"], context["evaluated_level"] = self.compute_completude(
context["total_skill"], gymnast_nb_known_skills, max_rank_skill
)
return context return context

View File

@ -1,3 +1,36 @@
from django.test import TestCase from datetime import date
from .models import Gymnast
from datetime import datetime
import pytest
# Create your tests here.
def test_gymnast_tostring():
g = Gymnast(last_name="Pauchou", first_name="Fred")
assert str(g) == "Pauchou, Fred"
def test_gymnaste_get_age():
g = Gymnast(
last_name="Pauchou",
first_name="Fred",
birthdate=datetime.strptime("03/07/1985", "%d/%m/%Y"),
)
assert g.age == 35
def test_gymnaste_get_next_age():
g = Gymnast(
last_name="Pauchou",
first_name="Fred",
birthdate=datetime.strptime("03/07/1985", "%d/%m/%Y"),
)
assert g.next_age == 36
def test_gymnaste_next_birthday():
g = Gymnast(
last_name="Pauchou",
first_name="Fred",
birthdate=datetime.strptime("03/07/1985", "%d/%m/%Y"),
)
assert g.next_birthday == datetime.strptime("03/07/2021", "%d/%m/%Y")

View File

@ -50,4 +50,4 @@ gymnast_urlpatterns = [
path( path(
r"edit/<int:gymnast_id>/", views.gymnast_create_or_update, name="gymnast_update" r"edit/<int:gymnast_id>/", views.gymnast_create_or_update, name="gymnast_update"
), ),
] ]

View File

@ -11,7 +11,15 @@ from .forms import GymnastForm
from ultron.followup.models import Event from ultron.followup.models import Event
from ultron.objective.models import Educative, Plan from ultron.objective.models import Educative, Plan
from ultron.followup.forms import GymnastHasRoutineForm from ultron.followup.forms import GymnastHasRoutineForm
from ultron.followup.models import Chrono, LearnedSkill, MindState, Skill, Point, Accident, HeightWeight from ultron.followup.models import (
Chrono,
LearnedSkill,
MindState,
Skill,
Point,
Accident,
HeightWeight,
)
import simplejson import simplejson
import pendulum import pendulum
@ -46,7 +54,7 @@ def gymnast_listing(request):
Liste tous les gymnasts connus Liste tous les gymnasts connus
""" """
gymnast_list = Gymnast.objects.all() gymnast_list = Gymnast.objects.all()
context = {'gymnast_list': gymnast_list} context = {"gymnast_list": gymnast_list}
return render(request, "peoples/gymnasts/list.html", context) return render(request, "peoples/gymnasts/list.html", context)
@ -56,65 +64,105 @@ def gymnast_details(request, gymnast_id):
""" """
Récupère toutes les informations d'un gymnaste. Récupère toutes les informations d'un gymnaste.
""" """
gymnast = get_object_or_404(Gymnast, pk=gymnast_id) gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
context = {} # devrait disparaitre context = {} # devrait disparaitre
context = gymnast.get_informations_from_level() # devrait disparaitre context = gymnast.get_informations_from_level() # devrait disparaitre
context.update(gymnast.get_informations_from_rank()) # devrait disparaitre context.update(gymnast.get_informations_from_rank()) # devrait disparaitre
gymnast_nb_known_skills = gymnast.known_skills.distinct('skill').count() # devrait disparaitre gymnast_nb_known_skills = gymnast.known_skills.distinct(
context["gymnast_nb_known_skills"] = gymnast_nb_known_skills # devrait disparaitre "skill"
).count() # devrait disparaitre
context["gymnast_nb_known_skills"] = gymnast_nb_known_skills # devrait disparaitre
planified_learn = Plan.objects.filter(gymnast=gymnast_id).order_by('-date') # devrait disparaitre ? planified_learn = Plan.objects.filter(gymnast=gymnast_id).order_by(
"-date"
) # devrait disparaitre ?
context["planified_learn"] = planified_learn context["planified_learn"] = planified_learn
learnedskills_list = LearnedSkill.objects.filter(gymnast=gymnast_id).order_by('-date')[:10] learnedskills_list = LearnedSkill.objects.filter(gymnast=gymnast_id).order_by(
"-date"
)[:10]
nb_skill = Skill.objects.all().count() nb_skill = Skill.objects.all().count()
nb_known_skill = LearnedSkill.objects.filter(gymnast=gymnast_id).distinct('skill').count() nb_known_skill = (
percentage_known_skill = ( nb_known_skill / nb_skill ) * 100 LearnedSkill.objects.filter(gymnast=gymnast_id).distinct("skill").count()
chronos_list = Chrono.objects.filter(gymnast=gymnast_id).order_by('-date')[:10] )
straightjump_score = Chrono.objects.filter(gymnast=gymnast_id).filter(type=0).order_by('-date') percentage_known_skill = (nb_known_skill / nb_skill) * 100
best_straightjump = Chrono.objects.filter(gymnast=gymnast_id).filter(type=0).order_by('-score')[:1] chronos_list = Chrono.objects.filter(gymnast=gymnast_id).order_by("-date")[:10]
best_routine = Chrono.objects.filter(gymnast=gymnast_id).filter(type=1).order_by('-score')[:1] straightjump_score = (
routine_score = Chrono.objects.filter(gymnast=gymnast_id).filter(type=1).order_by('-date') Chrono.objects.filter(gymnast=gymnast_id).filter(type=0).order_by("-date")
)
best_straightjump = (
Chrono.objects.filter(gymnast=gymnast_id).filter(type=0).order_by("-score")[:1]
)
best_routine = (
Chrono.objects.filter(gymnast=gymnast_id).filter(type=1).order_by("-score")[:1]
)
routine_score = (
Chrono.objects.filter(gymnast=gymnast_id).filter(type=1).order_by("-date")
)
points_routine_1_list = Point.objects.filter(gymnast=gymnast_id).filter(routine_type=0).order_by('-event__datebegin') points_routine_1_list = (
points_routine_2_list = Point.objects.filter(gymnast=gymnast_id).filter(routine_type=1).order_by('-event__datebegin') Point.objects.filter(gymnast=gymnast_id)
points_routine_final_list = Point.objects.filter(gymnast=gymnast_id).filter(routine_type=2).order_by('-event__datebegin') .filter(routine_type=0)
.order_by("-event__datebegin")
)
points_routine_2_list = (
Point.objects.filter(gymnast=gymnast_id)
.filter(routine_type=1)
.order_by("-event__datebegin")
)
points_routine_final_list = (
Point.objects.filter(gymnast=gymnast_id)
.filter(routine_type=2)
.order_by("-event__datebegin")
)
# Devrait être dans un template tags # Devrait être dans un template tags
nb_skill_chained = Skill.objects.filter(known_by__gymnast=gymnast_id, known_by__cando=3).distinct().count() nb_skill_chained = (
Skill.objects.filter(known_by__gymnast=gymnast_id, known_by__cando=3)
.distinct()
.count()
)
nb_skill_not_chained = Skill.objects.filter(known_by__gymnast=gymnast_id, known_by__cando=2).exclude( nb_skill_not_chained = (
known_by__gymnast=gymnast.id, known_by__cando=3 Skill.objects.filter(known_by__gymnast=gymnast_id, known_by__cando=2)
).distinct().count() .exclude(known_by__gymnast=gymnast.id, known_by__cando=3)
.distinct()
.count()
)
nb_skill_whith_help = Skill.objects.filter(known_by__gymnast=gymnast_id, known_by__cando=1).exclude( nb_skill_whith_help = (
known_by__gymnast=gymnast.id, known_by__cando__gte=2 Skill.objects.filter(known_by__gymnast=gymnast_id, known_by__cando=1)
).distinct().count() .exclude(known_by__gymnast=gymnast.id, known_by__cando__gte=2)
.distinct()
.count()
)
height_weight = HeightWeight.objects.filter(gymnast=gymnast_id).order_by('-date')[:1] height_weight = HeightWeight.objects.filter(gymnast=gymnast_id).order_by("-date")[
:1
]
nb_unknown_skill = nb_skill - gymnast_nb_known_skills nb_unknown_skill = nb_skill - gymnast_nb_known_skills
context['gymnast'] = gymnast context["gymnast"] = gymnast
context['learnedskills_list'] = learnedskills_list context["learnedskills_list"] = learnedskills_list
context['chronos_list'] = chronos_list context["chronos_list"] = chronos_list
context['straightjump_score'] = straightjump_score context["straightjump_score"] = straightjump_score
context['routine_score'] = routine_score context["routine_score"] = routine_score
context['best_routine'] = best_routine context["best_routine"] = best_routine
context['best_straightjump'] = best_straightjump context["best_straightjump"] = best_straightjump
context['nb_skill'] = nb_skill context["nb_skill"] = nb_skill
context['nb_known_skill'] = nb_known_skill context["nb_known_skill"] = nb_known_skill
context['points_routine_1_list'] = points_routine_1_list context["points_routine_1_list"] = points_routine_1_list
context['points_routine_2_list'] = points_routine_2_list context["points_routine_2_list"] = points_routine_2_list
context['points_routine_final_list'] = points_routine_final_list context["points_routine_final_list"] = points_routine_final_list
context['percentage_known_skill'] = percentage_known_skill context["percentage_known_skill"] = percentage_known_skill
context['nb_skill_chained'] = nb_skill_chained context["nb_skill_chained"] = nb_skill_chained
context['nb_skill_not_chained'] = nb_skill_not_chained context["nb_skill_not_chained"] = nb_skill_not_chained
context['nb_skill_whith_help'] = nb_skill_whith_help context["nb_skill_whith_help"] = nb_skill_whith_help
context['nb_unknown_skill'] = nb_unknown_skill context["nb_unknown_skill"] = nb_unknown_skill
context['height_weight'] = height_weight context["height_weight"] = height_weight
# context = { # context = {
# 'gymnast': gymnast, # 'gymnast': gymnast,
@ -143,7 +191,9 @@ def gymnast_display_event(request, gymnast_id):
""" """
today = pendulum.now().date() today = pendulum.now().date()
next_event_list = Event.objects.filter(gymnasts=gymnast_id, datebegin__gte=today) next_event_list = Event.objects.filter(gymnasts=gymnast_id, datebegin__gte=today)
previous_event_list = Event.objects.filter(gymnasts=gymnast_id, datebegin__lte=today) previous_event_list = Event.objects.filter(
gymnasts=gymnast_id, datebegin__lte=today
)
context = { context = {
"next_event_list": next_event_list, "next_event_list": next_event_list,
@ -160,10 +210,7 @@ def gymnast_display_accident(request, gymnast_id):
""" """
accident_list = Accident.objects.filter(gymnast=gymnast_id) accident_list = Accident.objects.filter(gymnast=gymnast_id)
context = { context = {"accident_list": accident_list, "gymnast_id": gymnast_id}
"accident_list": accident_list,
"gymnast_id": gymnast_id
}
return render(request, "peoples/gymnasts/list_accident.html", context) return render(request, "peoples/gymnasts/list_accident.html", context)
@ -174,16 +221,17 @@ def gymnast_display_phisiological(request, gymnast_id):
""" """
Renvoie les listes des tailles/poids, état d'esprit et accidents. Renvoie les listes des tailles/poids, état d'esprit et accidents.
""" """
accident_list = Accident.objects.filter(gymnast=gymnast_id).order_by('-date') accident_list = Accident.objects.filter(gymnast=gymnast_id).order_by("-date")
mindstate_list = MindState.objects.filter(gymnast=gymnast_id).order_by('-date') mindstate_list = MindState.objects.filter(gymnast=gymnast_id).order_by("-date")
height_weight_list = HeightWeight.objects.filter(gymnast=gymnast_id).order_by('-date') height_weight_list = HeightWeight.objects.filter(gymnast=gymnast_id).order_by(
"-date"
)
context = { context = {
'accident_list': accident_list, "accident_list": accident_list,
'mindstate_list': mindstate_list, "mindstate_list": mindstate_list,
'height_weight_list': height_weight_list, "height_weight_list": height_weight_list,
'gymnast_id': gymnast_id, "gymnast_id": gymnast_id,
} }
return render(request, "peoples/gymnasts/physiological_followup.html", context) return render(request, "peoples/gymnasts/physiological_followup.html", context)
@ -253,8 +301,7 @@ def gymnast_display_routines(request, gymnast_id):
@login_required @login_required
@require_http_methods(["GET", "POST"]) @require_http_methods(["GET", "POST"])
def link_routine_to_gymnast(request, gymnast_id=None): def link_routine_to_gymnast(request, gymnast_id=None):
""" """ """
"""
if gymnast_id: if gymnast_id:
gymnast = get_object_or_404(Gymnast, pk=gymnast_id) gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
@ -289,7 +336,7 @@ def gymnast_create_or_update(request, gymnast_id=None):
if gymnast_id: if gymnast_id:
gymnast = get_object_or_404(Gymnast, pk=gymnast_id) gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
data = {'club_related': gymnast.club} data = {"club_related": gymnast.club}
else: else:
gymnast = None gymnast = None
data = {} data = {}
@ -323,34 +370,42 @@ def gymnast_display_skill(request, gymnast_id):
context = {} context = {}
gymnast = get_object_or_404(Gymnast, pk=gymnast_id) gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
gymnast_nb_known_skills = gymnast.known_skills.distinct('skill').count() gymnast_nb_known_skills = gymnast.known_skills.distinct("skill").count()
context = gymnast.get_informations_from_level() context = gymnast.get_informations_from_level()
context.update(gymnast.get_informations_from_rank()) context.update(gymnast.get_informations_from_rank())
planified_skill = Skill.objects.filter(plan__gymnast=gymnast.id).order_by('-plan__date').annotate(plan_date=F("plan__date")) planified_skill = (
Skill.objects.filter(plan__gymnast=gymnast.id)
.order_by("-plan__date")
.annotate(plan_date=F("plan__date"))
)
context["planified_skill"] = planified_skill context["planified_skill"] = planified_skill
if gymnast.gender: if gymnast.gender:
context["skill_by_age"] = Skill.objects.filter(age_girl__lte=gymnast.age).exclude( context["skill_by_age"] = Skill.objects.filter(
known_by__gymnast=gymnast.id age_girl__lte=gymnast.age
) ).exclude(known_by__gymnast=gymnast.id)
else: else:
context["skill_by_age"] = Skill.objects.filter(age_boy__lte=gymnast.age).exclude( context["skill_by_age"] = Skill.objects.filter(
known_by__gymnast=gymnast.id age_boy__lte=gymnast.age
) ).exclude(known_by__gymnast=gymnast.id)
skill_whith_help = Skill.objects.filter(known_by__gymnast=gymnast_id, known_by__cando=1).exclude( skill_whith_help = (
known_by__gymnast=gymnast.id, known_by__cando__gte=2 Skill.objects.filter(known_by__gymnast=gymnast_id, known_by__cando=1)
).distinct() .exclude(known_by__gymnast=gymnast.id, known_by__cando__gte=2)
.distinct()
)
skill_not_chained = Skill.objects.filter(known_by__gymnast=gymnast_id, known_by__cando=2).exclude( skill_not_chained = (
known_by__gymnast=gymnast.id, known_by__cando=3 Skill.objects.filter(known_by__gymnast=gymnast_id, known_by__cando=2)
).distinct() .exclude(known_by__gymnast=gymnast.id, known_by__cando=3)
.distinct()
)
context["gymnast"] = gymnast context["gymnast"] = gymnast
context["skill_whith_help"] = skill_whith_help context["skill_whith_help"] = skill_whith_help
context["skill_not_chained"] = skill_not_chained context["skill_not_chained"] = skill_not_chained
context["gymnast_nb_known_skills"] = gymnast_nb_known_skills context["gymnast_nb_known_skills"] = gymnast_nb_known_skills
return render(request, "peoples/gymnasts/list_skill.html", context) return render(request, "peoples/gymnasts/list_skill.html", context)

View File

@ -22,36 +22,34 @@ from .models import (
class EventTypeAdmin(admin.ModelAdmin): class EventTypeAdmin(admin.ModelAdmin):
model = EventType model = EventType
list_display = ('name', 'acronym') list_display = ("name", "acronym")
ordering = ('name',) ordering = ("name",)
search_fields = ('name', 'acronym') search_fields = ("name", "acronym")
class EventAdmin(ForeignKeyAutocompleteAdmin): class EventAdmin(ForeignKeyAutocompleteAdmin):
model = Event model = Event
fields = ('name', 'eventtype', 'place', 'datebegin', 'dateend', 'informations') fields = ("name", "eventtype", "place", "datebegin", "dateend", "informations")
list_display = ('name', 'eventtype', 'place', 'datebegin') list_display = ("name", "eventtype", "place", "datebegin")
ordering = ('name',) ordering = ("name",)
list_filter = ('eventtype',) list_filter = ("eventtype",)
search_fields = ('name',) search_fields = ("name",)
autocomplete_fields = ( autocomplete_fields = ("eventtype",)
'eventtype',
)
# related_search_fields = { # related_search_fields = {
# 'place': ('name', 'city'), # 'place': ('name', 'city'),
# } # }
# filter_horizontal = ('gymnasts', 'club') # filter_horizontal = ('gymnasts', 'club')
# filter_horizontal = ('gymnasts',) # filter_horizontal = ('gymnasts',)
class Event_ParticipationAdmin(admin.ModelAdmin): class Event_ParticipationAdmin(admin.ModelAdmin):
model = Event_Participation model = Event_Participation
fields = ('event', 'gymnast', 'rank') fields = ("event", "gymnast", "rank")
list_display = ('event', 'gymnast', 'rank') list_display = ("event", "gymnast", "rank")
admin.site.register(EventType, EventTypeAdmin) admin.site.register(EventType, EventTypeAdmin)

View File

@ -2,5 +2,5 @@ from django.apps import AppConfig
class PlanningConfig(AppConfig): class PlanningConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField' default_auto_field = "django.db.models.BigAutoField"
name = 'ultron.planning' name = "ultron.planning"

View File

@ -1,4 +1,3 @@
from datetime import date from datetime import date
from django import forms from django import forms
@ -7,6 +6,7 @@ from django.contrib.admin.widgets import FilteredSelectMultiple
from ultron.people.models import Gymnast from ultron.people.models import Gymnast
from .models import Event from .models import Event
class EventForm(forms.ModelForm): class EventForm(forms.ModelForm):
# gymnasts = forms.ModelMultipleChoiceField(queryset=Gymnast.objects.all(), widget=FilteredSelectMultiple('Gymnast(s)', is_stacked=False)) # gymnasts = forms.ModelMultipleChoiceField(queryset=Gymnast.objects.all(), widget=FilteredSelectMultiple('Gymnast(s)', is_stacked=False))
@ -14,37 +14,37 @@ class EventForm(forms.ModelForm):
class Meta: class Meta:
model = Event model = Event
fields = ( fields = (
'name', "name",
'datebegin', "datebegin",
'dateend', "dateend",
'place', "place",
'eventtype', "eventtype",
'informations', "informations",
) # , 'gymnasts' ) # , 'gymnasts'
widgets = { widgets = {
'place': forms.HiddenInput(), "place": forms.HiddenInput(),
# 'gymnasts': forms.ModelMultipleChoiceField(queryset=Gymnast.objects.all(), widget=FilteredSelectMultiple('Gymnast(s)', is_stacked=False)), # 'gymnasts': forms.ModelMultipleChoiceField(queryset=Gymnast.objects.all(), widget=FilteredSelectMultiple('Gymnast(s)', is_stacked=False)),
# 'gymnasts': forms.MultipleChoiceField(choices=MYCHOICES, widget=forms.SelectMultiple) # 'gymnasts': forms.MultipleChoiceField(choices=MYCHOICES, widget=forms.SelectMultiple)
'eventtype': forms.Select(attrs={'class': 'form-control'}), "eventtype": forms.Select(attrs={"class": "form-control"}),
'name': forms.TextInput( "name": forms.TextInput(
attrs={'class': 'form-control', 'placeholder': 'Even\'s name'} attrs={"class": "form-control", "placeholder": "Even's name"}
), ),
'datebegin': forms.DateTimeInput( "datebegin": forms.DateTimeInput(
attrs={ attrs={
'class': 'form-control datetimepicker', "class": "form-control datetimepicker",
'placeholder': date.today().strftime('%Y-%m-%d 08:00'), "placeholder": date.today().strftime("%Y-%m-%d 08:00"),
} }
), ),
'dateend': forms.DateTimeInput( "dateend": forms.DateTimeInput(
attrs={ attrs={
'class': 'form-control datetimepicker', "class": "form-control datetimepicker",
'placeholder': date.today().strftime('%Y-%m-%d 18:00'), "placeholder": date.today().strftime("%Y-%m-%d 18:00"),
} }
), ),
'informations': forms.Textarea( "informations": forms.Textarea(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Informations about the event…', "placeholder": "Informations about the event…",
} }
), ),
} }
@ -52,9 +52,9 @@ class EventForm(forms.ModelForm):
place_related = forms.CharField( place_related = forms.CharField(
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'class': 'form-control', "class": "form-control",
'placeholder': 'Searching place…', "placeholder": "Searching place…",
'data-ref': '#id_place', "data-ref": "#id_place",
} }
) )
) )
@ -62,4 +62,4 @@ class EventForm(forms.ModelForm):
# class Media: # class Media:
# css = {'all':('/static/admin/css/widgets.css',),} # css = {'all':('/static/admin/css/widgets.css',),}
# js = ('/admin/jquery.js','/admin/jsi18n/') # OLD # js = ('/admin/jquery.js','/admin/jsi18n/') # OLD
# js = ('/admin/jsi18n/', ) # NEW # js = ('/admin/jsi18n/', ) # NEW

View File

@ -9,62 +9,118 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('people', '0001_initial'), ("people", "0001_initial"),
('location', '0001_initial'), ("location", "0001_initial"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Event', name="Event",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('datebegin', models.DateTimeField(verbose_name='Début')), "id",
('dateend', models.DateTimeField(blank=True, verbose_name='Fin')), models.BigAutoField(
('informations', models.TextField(blank=True, help_text='Only MarkDown is authorized', null=True, verbose_name='Comments')), auto_created=True,
('name', models.CharField(max_length=255, verbose_name='Nom')), primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("datebegin", models.DateTimeField(verbose_name="Début")),
("dateend", models.DateTimeField(blank=True, verbose_name="Fin")),
(
"informations",
models.TextField(
blank=True,
help_text="Only MarkDown is authorized",
null=True,
verbose_name="Comments",
),
),
("name", models.CharField(max_length=255, verbose_name="Nom")),
], ],
options={ options={
'verbose_name': 'Event', "verbose_name": "Event",
'verbose_name_plural': 'Event', "verbose_name_plural": "Event",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='EventType', name="EventType",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=255, verbose_name='Nom')), "id",
('acronym', models.CharField(max_length=15, verbose_name='Acronyme')), models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=255, verbose_name="Nom")),
("acronym", models.CharField(max_length=15, verbose_name="Acronyme")),
], ],
options={ options={
'verbose_name': 'Event Type', "verbose_name": "Event Type",
'verbose_name_plural': 'Event Types', "verbose_name_plural": "Event Types",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='Event_Participation', name="Event_Participation",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('rank', models.PositiveSmallIntegerField(default=0)), "id",
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='planning.event')), models.BigAutoField(
('gymnast', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='people.gymnast')), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("rank", models.PositiveSmallIntegerField(default=0)),
(
"event",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="planning.event"
),
),
(
"gymnast",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="people.gymnast"
),
),
], ],
options={ options={
'verbose_name': 'Event Participation', "verbose_name": "Event Participation",
}, },
), ),
migrations.AddField( migrations.AddField(
model_name='event', model_name="event",
name='eventtype', name="eventtype",
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='planning.eventtype', verbose_name='Type'), field=models.ForeignKey(
default=None,
on_delete=django.db.models.deletion.CASCADE,
to="planning.eventtype",
verbose_name="Type",
),
), ),
migrations.AddField( migrations.AddField(
model_name='event', model_name="event",
name='gymnasts', name="gymnasts",
field=models.ManyToManyField(related_name='participate_to', through='planning.Event_Participation', to='people.Gymnast', verbose_name='Participants'), field=models.ManyToManyField(
related_name="participate_to",
through="planning.Event_Participation",
to="people.Gymnast",
verbose_name="Participants",
),
), ),
migrations.AddField( migrations.AddField(
model_name='event', model_name="event",
name='place', name="place",
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='location.place'), field=models.ForeignKey(
default=None,
on_delete=django.db.models.deletion.CASCADE,
to="location.place",
),
), ),
] ]

View File

@ -5,7 +5,11 @@ from django.db import models
import pendulum import pendulum
from ultron.tools.models import Markdownizable, Temporizable, get_number_of_weeks_between from ultron.tools.models import (
Markdownizable,
Temporizable,
get_number_of_weeks_between,
)
from ultron.people.models import Gymnast from ultron.people.models import Gymnast
from ultron.location.models import Place from ultron.location.models import Place
@ -15,14 +19,14 @@ from ultron.location.models import Place
class EventType(models.Model): class EventType(models.Model):
""" """
Classe représentant les types d'évènements. Classe représentant les types d'évènements.
C'est un dictionnaire fini : C'est un dictionnaire fini :
- compétiton qualificative, - compétiton qualificative,
- compétition finale, - compétition finale,
- démonstration, - démonstration,
- -
""" """
class Meta: class Meta:
verbose_name = "Event Type" verbose_name = "Event Type"
@ -38,20 +42,18 @@ class EventType(models.Model):
class Event(Markdownizable, Temporizable): class Event(Markdownizable, Temporizable):
"""Classe représentant les évènements. """Classe représentant les évènements.
Un évènement est caractérisé par : Un évènement est caractérisé par :
* un nom, * un nom,
* un lieu (place), * un lieu (place),
* un type (compétition, démonstration, ), * un type (compétition, démonstration, ),
* des gymnastes (participation prévue). * des gymnastes (participation prévue).
""" """
class Meta: class Meta:
verbose_name = "Event" verbose_name = "Event"
verbose_name_plural = "Event" verbose_name_plural = "Event"
place = models.ForeignKey( place = models.ForeignKey(Place, on_delete=models.CASCADE, default=None)
Place, on_delete=models.CASCADE, default=None
)
eventtype = models.ForeignKey( eventtype = models.ForeignKey(
EventType, verbose_name="Type", on_delete=models.CASCADE, default=None EventType, verbose_name="Type", on_delete=models.CASCADE, default=None
) )
@ -72,9 +74,9 @@ class Event(Markdownizable, Temporizable):
def checkdates(self): def checkdates(self):
""" """
Fonction assignant la date de fin d'un évènement à la date de début, si la date Fonction assignant la date de fin d'un évènement à la date de début, si la date
de fin n'est pas définie, l'heure de fin est par défaut 18h00. de fin n'est pas définie, l'heure de fin est par défaut 18h00.
""" """
if self.dateend is None and self.datebegin is not None: if self.dateend is None and self.datebegin is not None:
self.dateend = datetime.combine(self.datebegin.date(), time(18, 0)) self.dateend = datetime.combine(self.datebegin.date(), time(18, 0))
@ -85,8 +87,8 @@ class Event(Markdownizable, Temporizable):
class Event_Participation(models.Model): class Event_Participation(models.Model):
""" """ """
"""
class Meta: class Meta:
verbose_name = "Event Participation" verbose_name = "Event Participation"
@ -95,4 +97,4 @@ class Event_Participation(models.Model):
rank = models.PositiveSmallIntegerField(default=0) rank = models.PositiveSmallIntegerField(default=0)
def __str__(self): def __str__(self):
return "%s to %s" % (self.gymnast, self.event) return "%s to %s" % (self.gymnast, self.event)

View File

@ -18,6 +18,7 @@ from .forms import EventForm
# import pendulum # import pendulum
import simplejson import simplejson
# import collections # import collections
# import locale # import locale
@ -47,7 +48,7 @@ def event_lookup(request):
@require_http_methods(["GET", "POST"]) @require_http_methods(["GET", "POST"])
def event_create_or_update(request, eventid=None): def event_create_or_update(request, eventid=None):
""" """
Création ou mise à jour d'un évènement. Création ou mise à jour d'un évènement.
""" """
if eventid: if eventid:
@ -141,8 +142,7 @@ def __get_event_list(request):
@login_required @login_required
@require_http_methods(["GET"]) @require_http_methods(["GET"])
def calendar(request): def calendar(request):
"""Récupère la liste de tous évènements suivant un pattern si celui-ci est définit. """Récupère la liste de tous évènements suivant un pattern si celui-ci est définit."""
"""
event_list = __get_event_list(request) event_list = __get_event_list(request)
context = {"event_list": event_list} context = {"event_list": event_list}
return render(request, "calendar.html", context) return render(request, "calendar.html", context)

View File

@ -4,7 +4,7 @@ from .models import Profile
class ProfileAdmin(admin.ModelAdmin): class ProfileAdmin(admin.ModelAdmin):
model = Profile model = Profile
list_display = ('user', 'template_color', 'sidebar_color') list_display = ("user", "template_color", "sidebar_color")
admin.site.register(Profile, ProfileAdmin) admin.site.register(Profile, ProfileAdmin)

View File

@ -2,5 +2,5 @@ from django.apps import AppConfig
class ProfileConfig(AppConfig): class ProfileConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField' default_auto_field = "django.db.models.BigAutoField"
name = 'ultron.profiles' name = "ultron.profiles"

View File

@ -9,18 +9,18 @@ class ProfileForm(forms.ModelForm):
class Meta: class Meta:
model = Profile model = Profile
fields = ( fields = (
'template_color', "template_color",
'sidebar_color', "sidebar_color",
'is_sidebar_minified', "is_sidebar_minified",
) )
widgets = { widgets = {
'template_color': forms.Select(attrs={'class': 'form-control'}), "template_color": forms.Select(attrs={"class": "form-control"}),
'sidebar_color': forms.Select(attrs={'class': 'form-control'}), "sidebar_color": forms.Select(attrs={"class": "form-control"}),
'is_sidebar_minified': forms.CheckboxInput( "is_sidebar_minified": forms.CheckboxInput(
attrs={ attrs={
'class': 'bootstrap-switch mt-0', "class": "bootstrap-switch mt-0",
'data-on-label': '<i class="tim-icons icon-check-2 text-success"></i>', "data-on-label": '<i class="tim-icons icon-check-2 text-success"></i>',
'data-off-label': '<i class="tim-icons icon-simple-remove text-danger"></i>', "data-off-label": '<i class="tim-icons icon-simple-remove text-danger"></i>',
} }
), ),
} }

View File

@ -15,13 +15,47 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Profile', name="Profile",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('template_color', models.PositiveSmallIntegerField(choices=[(0, 'Dark'), (1, 'Light')], default=0, verbose_name='Template')), "id",
('sidebar_color', models.PositiveSmallIntegerField(choices=[(0, 'Purple'), (1, 'Blue'), (2, 'Green'), (3, 'Orange'), (4, 'Red')], default=0, verbose_name='Sidebar')), models.BigAutoField(
('is_sidebar_minified', models.BooleanField(default=False)), auto_created=True,
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"template_color",
models.PositiveSmallIntegerField(
choices=[(0, "Dark"), (1, "Light")],
default=0,
verbose_name="Template",
),
),
(
"sidebar_color",
models.PositiveSmallIntegerField(
choices=[
(0, "Purple"),
(1, "Blue"),
(2, "Green"),
(3, "Orange"),
(4, "Red"),
],
default=0,
verbose_name="Sidebar",
),
),
("is_sidebar_minified", models.BooleanField(default=False)),
(
"user",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
], ],
), ),
] ]

View File

@ -12,27 +12,26 @@ from .models import Profile
User = get_user_model() User = get_user_model()
@login_required @login_required
@require_http_methods(["GET", "POST"]) @require_http_methods(["GET", "POST"])
def profile_update(request): def profile_update(request):
"""Modification du profil de l'utilisateur connecté """Modification du profil de l'utilisateur connecté"""
"""
try: try:
profile = request.user.profile profile = request.user.profile
except Exception: # don't do this ! except Exception: # don't do this !
profile = Profile.objects.create(user=request.user) profile = Profile.objects.create(user=request.user)
if request.method == 'POST': if request.method == "POST":
form = ProfileForm(request.POST, instance=profile) form = ProfileForm(request.POST, instance=profile)
if form.is_valid(): if form.is_valid():
form.save() form.save()
request.session['template'] = profile.template_color request.session["template"] = profile.template_color
request.session['sidebar'] = profile.sidebar_color request.session["sidebar"] = profile.sidebar_color
request.session['is_sidebar_minified'] = profile.is_sidebar_minified request.session["is_sidebar_minified"] = profile.is_sidebar_minified
return HttpResponseRedirect("/") return HttpResponseRedirect("/")
@ -42,4 +41,4 @@ def profile_update(request):
context = { context = {
"form": form, "form": form,
} }
return render(request, 'profiles/update.html', context) return render(request, "profiles/update.html", context)

View File

@ -9,29 +9,29 @@ import markdown
def get_number_of_weeks_between(start, stop): def get_number_of_weeks_between(start, stop):
""" """
Renvoie le nombre de semaines entre deux dates. Renvoie le nombre de semaines entre deux dates.
Par extension, cela permet de connaitre le nombre d'occurence d'un Par extension, cela permet de connaitre le nombre d'occurence d'un
évènement (entraînement, par exemple) hebdromadaire entre deux dates évènement (entraînement, par exemple) hebdromadaire entre deux dates
et ainsi pouvoir plannifier. et ainsi pouvoir plannifier.
:param start: date de début de la période :param start: date de début de la période
:type start: datetime.date :type start: datetime.date
:param stop: date de fin de la période :param stop: date de fin de la période
:type stop: datetime.date :type stop: datetime.date
:return: Le nombre de semaines entre les deux dates. :return: Le nombre de semaines entre les deux dates.
Remarks: Remarks:
Proposition d'utiliser isocalendar() sur une date. Proposition d'utiliser isocalendar() sur une date.
L'indice 1 de la valeur de retour donne la semaine correspondant. L'indice 1 de la valeur de retour donne la semaine correspondant.
Eg. Eg.
>>> from datetime import date >>> from datetime import date
>>> d = date(2020, 9, 27) >>> d = date(2020, 9, 27)
>>> d.isocalendar() >>> d.isocalendar()
(2020, 39, 7) (2020, 39, 7)
-> Est-ce qu'il ne suffirait pas de faire la différence ? -> Est-ce qu'il ne suffirait pas de faire la différence ?
""" """
tmp = stop - start tmp = stop - start
number_of_days = abs(tmp.days) number_of_days = abs(tmp.days)
@ -48,28 +48,28 @@ def get_number_of_weeks_between(start, stop):
class TemporizableQuerySet(models.QuerySet): class TemporizableQuerySet(models.QuerySet):
""" """
Classe permettant de spécifier le `QuerySet` de la classe `Temporizable`. Classe permettant de spécifier le `QuerySet` de la classe `Temporizable`.
""" """
def next(self, limit): def next(self, limit):
""" """
Renvoie la liste des prochains "temporizable" (par rapport à la date du jour). Renvoie la liste des prochains "temporizable" (par rapport à la date du jour).
:param limit: nombre d'éléments désirés. :param limit: nombre d'éléments désirés.
:type limit: int :type limit: int
:return: une liste de `limit` éléments temporizables. :return: une liste de `limit` éléments temporizables.
""" """
return self.filter(datebegin__gte=timezone.now()).order_by('datebegin')[0:limit] return self.filter(datebegin__gte=timezone.now()).order_by("datebegin")[0:limit]
def last(self, limit): def last(self, limit):
""" """
Renvoie la liste des derniers "temporizable" (par rapport à la date du jour). Renvoie la liste des derniers "temporizable" (par rapport à la date du jour).
:param limit: nombre d'éléments désirés. :param limit: nombre d'éléments désirés.
:type limit: int :type limit: int
:return: une liste de `limit` éléments temporizables :return: une liste de `limit` éléments temporizables
""" """
return self.filter(dateend__lte=timezone.now()).order_by('-dateend')[0:limit] return self.filter(dateend__lte=timezone.now()).order_by("-dateend")[0:limit]
# def get(self, date_string): # def get(self, date_string):
# """ # """
@ -87,52 +87,52 @@ class TemporizableQuerySet(models.QuerySet):
class Temporizable(models.Model): class Temporizable(models.Model):
""" """
Classe abstraite définissant une période comprise entre deux dates. Classe abstraite définissant une période comprise entre deux dates.
""" """
class Meta: class Meta:
abstract = True abstract = True
datebegin = models.DateTimeField(verbose_name='Début') datebegin = models.DateTimeField(verbose_name="Début")
dateend = models.DateTimeField(blank=True, verbose_name='Fin') dateend = models.DateTimeField(blank=True, verbose_name="Fin")
objects = models.Manager.from_queryset(TemporizableQuerySet)() objects = models.Manager.from_queryset(TemporizableQuerySet)()
def get_total_occurence(self): def get_total_occurence(self):
""" """
Renvoie le nombre de semaines entre les deux dates d'une instance de la Renvoie le nombre de semaines entre les deux dates d'une instance de la
classe `Temporizable`. classe `Temporizable`.
:return: nombre de semaines. :return: nombre de semaines.
""" """
return get_number_of_weeks_between(self.datebegin.date(), self.dateend.date()) return get_number_of_weeks_between(self.datebegin.date(), self.dateend.date())
def get_number_of_occurence_to_event(self, the_date): def get_number_of_occurence_to_event(self, the_date):
""" """
Renvoie le nombre semaines entre une date choisie et le début Renvoie le nombre semaines entre une date choisie et le début
(datebegin) d'une instance de la classe `Temporizable`. (datebegin) d'une instance de la classe `Temporizable`.
:param the_date: date par rapport à laquelle le calcul sera fait. :param the_date: date par rapport à laquelle le calcul sera fait.
:type the_date: datetime.date :type the_date: datetime.date
:return: nombre de semaines. :return: nombre de semaines.
""" """
return get_number_of_weeks_between(the_date, self.datebegin.date()) return get_number_of_weeks_between(the_date, self.datebegin.date())
def get_number_of_occurence_inbetween(self, the_date, rest=True): def get_number_of_occurence_inbetween(self, the_date, rest=True):
""" """
Renvoie le nombre semaines entre une date choisie et une instance de la Renvoie le nombre semaines entre une date choisie et une instance de la
classe `Temporizable`. Le calcul peut se faire soit entre la date classe `Temporizable`. Le calcul peut se faire soit entre la date
choisie et le date de fin d'une occurence de la classe, soit entre la choisie et le date de fin d'une occurence de la classe, soit entre la
date de début d'une occurence de la classe et la date choisie. date de début d'une occurence de la classe et la date choisie.
:param the_date: date par rapport à laquelle le calcul sera fait. :param the_date: date par rapport à laquelle le calcul sera fait.
:type the_date: datetime.date :type the_date: datetime.date
:param rest: paramètre définissant s'il faut calculer le reste des :param rest: paramètre définissant s'il faut calculer le reste des
occurences à venir (depuis `the_date` jusqu'à la date de fin) ou occurences à venir (depuis `the_date` jusqu'à la date de fin) ou
les occurences déjà passées (depuis la date de début jusqu'à les occurences déjà passées (depuis la date de début jusqu'à
`the_date`) `the_date`)
:type rest: booléen :type rest: booléen
:return: nombre de semaines. :return: nombre de semaines.
""" """
if rest: if rest:
return get_number_of_weeks_between(the_date, self.dateend.date()) return get_number_of_weeks_between(the_date, self.dateend.date())
else: else:
@ -150,8 +150,8 @@ class Markdownizable(models.Model):
informations = models.TextField( informations = models.TextField(
null=True, null=True,
blank=True, blank=True,
verbose_name='Comments', verbose_name="Comments",
help_text='Only MarkDown is authorized', help_text="Only MarkDown is authorized",
) )
def to_markdown(self): def to_markdown(self):