diff --git a/boatmovers/migrations/0008_auto_20220624_1135.py b/boatmovers/migrations/0008_auto_20220624_1135.py new file mode 100644 index 00000000..d5492e47 --- /dev/null +++ b/boatmovers/migrations/0008_auto_20220624_1135.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.12 on 2022-06-24 11:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('boatmovers', '0007_auto_20220624_0820'), + ] + + operations = [ + migrations.AddField( + model_name='race', + name='processed', + field=models.BooleanField(default=True), + ), + migrations.AlterField( + model_name='race', + name='crew_size', + field=models.IntegerField(default=1, verbose_name='Nr of rowers per crew (1, 2, 4, 8)'), + ), + ] diff --git a/boatmovers/migrations/0009_alter_race_crew_size.py b/boatmovers/migrations/0009_alter_race_crew_size.py new file mode 100644 index 00000000..4207ae30 --- /dev/null +++ b/boatmovers/migrations/0009_alter_race_crew_size.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2022-06-24 12:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('boatmovers', '0008_auto_20220624_1135'), + ] + + operations = [ + migrations.AlterField( + model_name='race', + name='crew_size', + field=models.IntegerField(choices=[(1, 1), (2, 2), (4, 4), (8, 8)], default=1, verbose_name='Nr of rowers per crew (1, 2, 4, 8)'), + ), + ] diff --git a/boatmovers/migrations/0010_remove_race_resultlist.py b/boatmovers/migrations/0010_remove_race_resultlist.py new file mode 100644 index 00000000..e6d9403e --- /dev/null +++ b/boatmovers/migrations/0010_remove_race_resultlist.py @@ -0,0 +1,17 @@ +# Generated by Django 3.2.12 on 2022-06-24 12:50 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('boatmovers', '0009_alter_race_crew_size'), + ] + + operations = [ + migrations.RemoveField( + model_name='race', + name='resultlist', + ), + ] diff --git a/boatmovers/migrations/0011_alter_race_processed.py b/boatmovers/migrations/0011_alter_race_processed.py new file mode 100644 index 00000000..f8b81cb7 --- /dev/null +++ b/boatmovers/migrations/0011_alter_race_processed.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2022-06-24 12:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('boatmovers', '0010_remove_race_resultlist'), + ] + + operations = [ + migrations.AlterField( + model_name='race', + name='processed', + field=models.BooleanField(default=False), + ), + ] diff --git a/boatmovers/models.py b/boatmovers/models.py index 8785c275..b2664c4b 100644 --- a/boatmovers/models.py +++ b/boatmovers/models.py @@ -52,6 +52,9 @@ class Crew(models.Model): def save(self, *args, **kwargs): super(Crew, self).save(*args, **kwargs) + def size(self): + return self.athletes.all().count() + class crewForm(forms.ModelForm): class Meta: model = Crew @@ -59,12 +62,13 @@ class crewForm(forms.ModelForm): class Race(models.Model): name = models.CharField(max_length=200) - resulturl = models.URLField(null=True) - date = models.DateField(default=current_day) - resultlist = models.ManyToManyField(Crew,through='Result') - crew_size = models.IntegerField(default=1,verbose_name='Nr of rowers per crew (1, 2, 4, 8)') + resulturl = models.URLField(null=True, verbose_name='URL Link to results') + date = models.DateField(default=current_day, verbose_name='Race Date') + #resultlist = models.ManyToManyField(Result,through='Result') + crew_size = models.IntegerField(default=1,verbose_name='Nr of rowers per crew (1, 2, 4, 8)', + choices=((1,1),(2,2),(4,4),(8,8))) verified = models.BooleanField(default=False) - processed = models.BooleanField(default=True) + processed = models.BooleanField(default=False) class Meta: unique_together = ('date','name') @@ -93,10 +97,87 @@ class Race(models.Model): super(Race, self).save(*args, **kwargs) + def validate(self): + if len(self.results.all()) < 2: + self.verified = False + self.save() + return False + + l = self.results.all()[0].crew.size() + for result in self.results.all(): + if result.crew.size() != l: + self.verified = False + self.save() + return False + + if l not in [1,2,4,8]: + self.verified = False + self.save() + return False + + results = self.results.all() + crews = [] + athletes = [] + for result in results: + crews.append(result.crew.id) + for athlete in result.crew.athletes.all(): + athletes.append(athlete.id) + + if len(crews) != len(set(crews)): + self.verified = False + self.save() + return False + + if len(athletes) != len(set(athletes)): + self.verified = False + self.save() + return False + + self.verified = True + self.save() + + def process(self): + if not self.verified: + if not self.validate(): + return False + + if self.processed: + return True + + # validate the race + results = self.results.all().order_by('order') + crews = [] + ranks = [] + + for result in results: + crew = result.crew + crewdict = {} + for athlete in crew.athletes.all(): + crewdict[athlete.id] = trueskill.Rating( + athlete.trueskill_mu, athlete.trueskill_sigma) + crews.append(crewdict) + ranks.append(result.order) + + rated_crews = trueskill.rate(crews, ranks) + + for crew in rated_crews: + + for id, rating in crew.items(): + athlete = Athlete.objects.get(id=id) + athlete.trueskill_mu = rating.mu + athlete.trueskill_sigma = rating.sigma + athlete.save() + + self.processed = True + self.save() + + return True + + class raceForm(forms.ModelForm): class Meta: model = Race - fields = ['name','date','resulturl','crew_size','resultlist'] + fields = ['name','date','resulturl','crew_size'] class Result(models.Model): @@ -107,7 +188,14 @@ class Result(models.Model): order = models.PositiveIntegerField() class Meta: - unique_together = ('crew','race','order') + unique_together = ('crew','order') + + def __str__(self): + return u'{r}: {o} - {c}'.format( + r=self.race, + o=self.order, + c=self.crew, + ) def save(self, *args, **kwargs): allresults = self.race.results.all() diff --git a/boatmovers/results.py b/boatmovers/results.py index ebfdc0df..168a51a6 100644 --- a/boatmovers/results.py +++ b/boatmovers/results.py @@ -38,30 +38,30 @@ class Result: def __init__(self, crews, name, validated=False, processed=False): self.crews = crews self.name = name - self.validated = validated + self.verified = validated self.processed = processed def validate(self): # crews need to be more than 2 if len(self.crews) < 2: - self.validated = False + self.verified = False return False # crews need to be all same length l = self.crews[0].size() for crew in self.crews: if crew.size() != l: - self.validated = False + self.verified = False return False # crew length need to be 1, 2, 4 or 8 if l not in [1,2,4,8]: - self.validated = False + self.verified = False return False # cannot have same crew multiple times in same race if len(self.crews) != len(set(self.crews)): - self.validated = False + self.verified = False return False # cannot have same athletes in different crews in same race @@ -71,14 +71,14 @@ class Result: allathletes.append(athlete) if len(allathletes) != len(set(allathletes)): - self.validated = False + self.verified = False return False - self.validated = True - return self.validated + self.verified = True + return self.verified def process(self): - if not self.validated: + if not self.verified: if not self.validate(): return False diff --git a/boatmovers/templates/boatmovers.html b/boatmovers/templates/boatmovers.html new file mode 100644 index 00000000..8337956e --- /dev/null +++ b/boatmovers/templates/boatmovers.html @@ -0,0 +1,69 @@ +
+
| Rank | +Score | +Name | + | Club | +Gender | +Year of Birth | +
|---|---|---|---|---|---|---|
| {{ forloop.counter }} | +{{ athlete.trueskill_exposed|floatformat:2 }} | +{{ athlete.first_name }} | +{{ athlete.last_name }} | +{{ athlete.club }} | +{{ athlete.gender }} | +{{ athlete.birth_year }} | +
+ This ranking was based on results from following races: +
++
| {{ race.date }} | {{ race.name }} | ++ View Race + | +
+ Unprocessed races +
++
| {{ race.date }} | {{ race.name }} | ++ Manage Race + | +
+ Add Athlete +
++ Add Crew +
+{% endif %} ++ Add Race +
+{% if user.is_authenticated and user.is_staff %} ++ Add Result +
+{% endif %} diff --git a/boatmovers/templates/boatmovers/race_form.html b/boatmovers/templates/boatmovers/race_form.html new file mode 100644 index 00000000..a9b32c5f --- /dev/null +++ b/boatmovers/templates/boatmovers/race_form.html @@ -0,0 +1,4 @@ + diff --git a/boatmovers/templates/boatmovers/result_form.html b/boatmovers/templates/boatmovers/result_form.html new file mode 100644 index 00000000..a9b32c5f --- /dev/null +++ b/boatmovers/templates/boatmovers/result_form.html @@ -0,0 +1,4 @@ + diff --git a/boatmovers/templates/race.html b/boatmovers/templates/race.html new file mode 100644 index 00000000..c26bcbff --- /dev/null +++ b/boatmovers/templates/race.html @@ -0,0 +1,45 @@ ++ {{ race.date }} +
++
| Order | +Crew | + |
|---|---|---|
| {{ result.order }} | +{{ result.crew.name }} | +
+ Race has been verified +
+{% if race.processed %} ++ Race has been processed +
+{% else %} ++ Race is not processed. Process Race +
+{% endif %} +{% else %} ++ Race is not verified. Verify Race +
+{% endif %} +{% if not race.verified and not race.processed %} ++ Add Result +
+{% endif %} +{% endif %} diff --git a/boatmovers/urls.py b/boatmovers/urls.py index 71b8da8e..0a849670 100644 --- a/boatmovers/urls.py +++ b/boatmovers/urls.py @@ -7,5 +7,10 @@ import boatmovers.views as views urlpatterns = [ url(r'athlete/add/$',views.AthleteCreateView.as_view(),name='athlete_add'), url(r'crew/add/$',views.CrewCreateView.as_view(),name='crew_add'), + url(r'race/add/$',views.RaceCreateView.as_view(),name='race_add'), + url(r'result/add/$',views.ResultCreateView.as_view(),name='result_add'), + url(r'race/(?P