Basic functionality is there
This commit is contained in:
23
boatmovers/migrations/0008_auto_20220624_1135.py
Normal file
23
boatmovers/migrations/0008_auto_20220624_1135.py
Normal file
@@ -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)'),
|
||||
),
|
||||
]
|
||||
18
boatmovers/migrations/0009_alter_race_crew_size.py
Normal file
18
boatmovers/migrations/0009_alter_race_crew_size.py
Normal file
@@ -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)'),
|
||||
),
|
||||
]
|
||||
17
boatmovers/migrations/0010_remove_race_resultlist.py
Normal file
17
boatmovers/migrations/0010_remove_race_resultlist.py
Normal file
@@ -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',
|
||||
),
|
||||
]
|
||||
18
boatmovers/migrations/0011_alter_race_processed.py
Normal file
18
boatmovers/migrations/0011_alter_race_processed.py
Normal file
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
69
boatmovers/templates/boatmovers.html
Normal file
69
boatmovers/templates/boatmovers.html
Normal file
@@ -0,0 +1,69 @@
|
||||
<p>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Rank</th>
|
||||
<th>Score</th>
|
||||
<th>Name</th><td></td>
|
||||
<th>Club</th>
|
||||
<th>Gender</th>
|
||||
<th>Year of Birth</th>
|
||||
</tr>
|
||||
{% for athlete in athletes %}
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ athlete.trueskill_exposed|floatformat:2 }}</td>
|
||||
<td>{{ athlete.first_name }}</td>
|
||||
<td>{{ athlete.last_name }}</td>
|
||||
<td>{{ athlete.club }}</td>
|
||||
<td>{{ athlete.gender }}</td>
|
||||
<td>{{ athlete.birth_year }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</p>
|
||||
<p>
|
||||
This ranking was based on results from following races:
|
||||
</p>
|
||||
<p>
|
||||
<table>
|
||||
{% for race in races %}
|
||||
<tr>
|
||||
<td>{{ race.date }}</td><td>{{ race.name }}</td>
|
||||
<td>
|
||||
<a href="race/{{ race.id }}">View Race</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</p>
|
||||
{% if user.is_authenticated and user.is_staff %}
|
||||
<p>
|
||||
Unprocessed races
|
||||
</p>
|
||||
<p>
|
||||
<table>
|
||||
{% for race in new_races %}
|
||||
<tr>
|
||||
<td>{{ race.date }}</td><td>{{ race.name }}</td>
|
||||
<td>
|
||||
<a href="race/{{ race.id }}">Manage Race</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</p>
|
||||
<p>
|
||||
<a href="athlete/add/">Add Athlete</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="crew/add/">Add Crew</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
<p>
|
||||
<a href="race/add/">Add Race</a>
|
||||
</p>
|
||||
{% if user.is_authenticated and user.is_staff %}
|
||||
<p>
|
||||
<a href="result/add/">Add Result</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
4
boatmovers/templates/boatmovers/race_form.html
Normal file
4
boatmovers/templates/boatmovers/race_form.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<form action="" method="post">{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<input type="submit" value="Create" />
|
||||
</form>
|
||||
4
boatmovers/templates/boatmovers/result_form.html
Normal file
4
boatmovers/templates/boatmovers/result_form.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<form action="" method="post">{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<input type="submit" value="Create" />
|
||||
</form>
|
||||
45
boatmovers/templates/race.html
Normal file
45
boatmovers/templates/race.html
Normal file
@@ -0,0 +1,45 @@
|
||||
<h1>
|
||||
{{ race.name }}
|
||||
</h1>
|
||||
<p>
|
||||
{{ race.date }}
|
||||
</p>
|
||||
<p>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Order</th>
|
||||
<th>Crew</th><td></td>
|
||||
</tr>
|
||||
{% for result in results %}
|
||||
<tr>
|
||||
<td>{{ result.order }}</td>
|
||||
<td>{{ result.crew.name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</p>
|
||||
{% if user.is_authenticated and user.is_staff %}
|
||||
{% if race.verified %}
|
||||
<p>
|
||||
Race has been verified
|
||||
</p>
|
||||
{% if race.processed %}
|
||||
<p>
|
||||
Race has been processed
|
||||
</p>
|
||||
{% else %}
|
||||
<p>
|
||||
Race is not processed. <a href="process/">Process Race</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p>
|
||||
Race is not verified. <a href="verify/">Verify Race</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if not race.verified and not race.processed %}
|
||||
<p>
|
||||
<a href="/boatmovers/result/add/">Add Result</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -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<id>\d+)/$',views.race_view,name='race_view'),
|
||||
url(r'race/(?P<id>\d+)/verify/$',views.race_verify,name='race_verify'),
|
||||
url(r'race/(?P<id>\d+)/process/$',views.race_process,name='race_process'),
|
||||
url(r'^$',views.boatmovers_view,name='boatmovers')
|
||||
]
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpResponse
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.urls import reverse
|
||||
|
||||
# Create your views here.
|
||||
from django.views.generic.edit import CreateView
|
||||
from boatmovers.models import Athlete, Crew
|
||||
from boatmovers.models import Athlete, Crew, Race, Result
|
||||
|
||||
class AthleteCreateView(CreateView):
|
||||
model = Athlete
|
||||
@@ -25,5 +27,59 @@ class CrewCreateView(CreateView):
|
||||
|
||||
success_url = '/boatmovers/'
|
||||
|
||||
class RaceCreateView(CreateView):
|
||||
model = Race
|
||||
fields = [
|
||||
'name',
|
||||
'resulturl',
|
||||
'date',
|
||||
'crew_size',
|
||||
#'resultlist',
|
||||
]
|
||||
|
||||
success_url = '/boatmovers/'
|
||||
|
||||
class ResultCreateView(CreateView):
|
||||
model = Result
|
||||
fields = [
|
||||
'crew',
|
||||
'race',
|
||||
'order'
|
||||
]
|
||||
|
||||
success_url = '/boatmovers/'
|
||||
|
||||
def boatmovers_view(request):
|
||||
return HttpResponse("1")
|
||||
athletes = Athlete.objects.all().order_by('-trueskill_exposed','-birth_year','last_name','first_name')
|
||||
|
||||
races = Race.objects.filter(verified=True,processed=True).order_by('-date')
|
||||
new_races = Race.objects.filter(processed=False).order_by('date')
|
||||
|
||||
return render(request,
|
||||
'boatmovers.html',
|
||||
{'athletes':athletes,
|
||||
'races': races,
|
||||
'new_races': new_races}
|
||||
)
|
||||
|
||||
def race_view(request,id=0):
|
||||
race = get_object_or_404(Race, pk=id)
|
||||
results = race.results.all().order_by('order')
|
||||
|
||||
return render(request,
|
||||
'race.html',
|
||||
{'race':race,
|
||||
'results':results}
|
||||
)
|
||||
|
||||
def race_verify(request, id=0):
|
||||
race = get_object_or_404(Race, pk=id)
|
||||
outcome = race.validate()
|
||||
|
||||
return HttpResponseRedirect(reverse('race_view',kwargs={'id':race.id}))
|
||||
|
||||
def race_process(request, id=0):
|
||||
race = get_object_or_404(Race, pk=id)
|
||||
outcome = race.process()
|
||||
|
||||
return HttpResponseRedirect(reverse('race_view',kwargs={'id':race.id}))
|
||||
|
||||
Reference in New Issue
Block a user