From 08c7562c514ad1b8f91b500fca4efac0db874582 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 26 May 2020 10:56:23 +0200 Subject: [PATCH] more foundation work for scoring --- rowers/admin.py | 10 ++++- rowers/courseutils.py | 13 ++++-- rowers/models.py | 12 +++++ rowers/scoring.py | 102 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 rowers/scoring.py diff --git a/rowers/admin.py b/rowers/admin.py index f0db40e8..490fe9c3 100644 --- a/rowers/admin.py +++ b/rowers/admin.py @@ -11,7 +11,7 @@ from .models import ( Team,TeamInvite,TeamRequest, WorkoutComment,C2WorldClassAgePerformance,PlannedSession, GeoCourse,GeoPolygon,GeoPoint,VirtualRace,VirtualRaceResult, - PaidPlan,IndoorVirtualRaceResult,ShareKey + PaidPlan,IndoorVirtualRaceResult,ShareKey, CourseStandard,StandardCollection, ) # Register your models here so you can use them in the Admin module @@ -141,6 +141,12 @@ class IndoorVirtualRaceResultAdmin(admin.ModelAdmin): class PaidPlanAdmin(admin.ModelAdmin): list_display = ('name','shortname','price','paymenttype','paymentprocessor','external_id') +class StandardCollectionAdmin(admin.ModelAdmin): + list_display = ('name','manager') + +class CourseStandardAdmin(admin.ModelAdmin): + list_display = ('name','standardcollection') + admin.site.unregister(User) admin.site.register(User,UserAdmin) admin.site.register(Workout,WorkoutAdmin) @@ -160,3 +166,5 @@ admin.site.register(VirtualRaceResult, VirtualRaceResultAdmin) admin.site.register(IndoorVirtualRaceResult, IndoorVirtualRaceResultAdmin) admin.site.register(PaidPlan,PaidPlanAdmin) admin.site.register(ShareKey,ShareKeyAdmin) +admin.site.register(CourseStandard,CourseStandardAdmin) +admin.site.register(StandardCollection,StandardCollectionAdmin) diff --git a/rowers/courseutils.py b/rowers/courseutils.py index 39fda8bf..6ff83fc7 100644 --- a/rowers/courseutils.py +++ b/rowers/courseutils.py @@ -2,6 +2,11 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals + + + + + # low level methods def coordinate_in_path(latitude,longitude, p): @@ -18,12 +23,12 @@ def time_in_path(df,p,maxmin='max',getall=False): if df.empty: return 0 - + latitude = df.latitude longitude = df.longitude f = lambda x: coordinate_in_path(x['latitude'],x['longitude'],p) - + df['inpolygon'] = df.apply(f,axis=1) if maxmin=='max': @@ -40,7 +45,7 @@ def time_in_path(df,p,maxmin='max',getall=False): raise InvalidTrajectoryError("Trajectory doesn't go through path") - + return 0 @@ -64,7 +69,7 @@ def coursetime_paths(data,paths,finalmaxmin='min'): entrytime = data['time'].max() entrydistance = data['cum_dist'].max() coursecompleted = False - + # corner case - empty list of paths if len(paths) == 0: return 0,True diff --git a/rowers/models.py b/rowers/models.py index 21861c49..dcf75050 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2196,6 +2196,10 @@ from django.core.validators import RegexValidator,validate_email class StandardCollection(models.Model): name = models.CharField(max_length=150) + manager = models.ForeignKey(User, null=True,on_delete=models.CASCADE) + + def __str__(self): + return self.name class CourseStandard(models.Model): name = models.CharField(max_length=150) @@ -2211,6 +2215,14 @@ class CourseStandard(models.Model): skillclass = models.CharField(max_length=150) standardcollection = models.ForeignKey(StandardCollection,on_delete=models.CASCADE) + class Meta: + unique_together = ('name','sex','agemin', + 'agemax','boatclass','boattype','weightclass','adaptiveclass', + 'skillclass','standardcollection') + + def __str__(self): + return self.name + registerchoices = ( ('windowstart','Start of challenge Window'), ('windowend','End of challenge Window'), diff --git a/rowers/scoring.py b/rowers/scoring.py new file mode 100644 index 00000000..a4a6bd74 --- /dev/null +++ b/rowers/scoring.py @@ -0,0 +1,102 @@ +from rowers.models import StandardCollection,CourseStandard + +import pandas as pd +import arrow +import datetime + +def save_scoring(name,user,filename,id=0): + if id==0: + collection = StandardCollection(name=name,manager=user) + collection.save() + standards = CourseStandard.objects.filter(standardcollection=collection) + for standard in standards: + standard.delete() + else: + try: + collection = StandardCollection.objects.get(id=id) + collection.name = name + collection.save() + + except StandardCollection.DoesNotExist: + return 0 + + try: + df = pd.read_csv(filename) + except: + return 0 + + df = df.drop_duplicates(['Name']) + + for index, row in df.iterrows(): + try: + name = row['Name'] + except KeyError: + continue + + try: + coursedistance = row['CourseDistance'] + coursetime = row['CourseStandard'] + t = datetime.datetime.strptime(coursetime,'%M:%S.%f') + delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second,microseconds=t.microsecond) + seconds = delta.total_seconds() + + coursestandard = coursedistance/seconds + except KeyError: + continue + + try: + agemin = row['MinAge'] + agemax = row['MaxAge'] + agemin = int(agemin) + agemax = int(agemax) + except KeyError: + agemin = 0 + agemax = 120 + + try: + boatclass = row['BoatClass'] + except KeyError: + boatclass = 'water' + + try: + boattype = row['BoatType'] + except KeyError: + boattype = '1x' + + try: + sex = row['Gender'] + except KeyError: + sex = 'F' + + try: + weightclass = row['WeightClass'] + except KeyError: + weightclass = 'hwt' + + try: + adaptiveclass = row['AdaptiveClass'] + except KeyError: + adaptiveclass = None + + try: + skillclass = row['SkillClass'] + except KeyError: + skillclass = 'Open' + + # some testing + standard = CourseStandard( + name=name, + coursedistance=coursedistance, + coursestandard=coursestandard, + agemin=agemin, + agemax=agemax, + boatclass=boatclass, + boattype=boattype, + sex=sex, + weightclass=weightclass, + adaptiveclass=adaptiveclass, + skillclass=skillclass, + standardcollection = collection, + ) + + standard.save()