import math import statistics from operator import itemgetter from django.core.management.base import BaseCommand, CommandError from django_scopes import scope from pretalx.event.models import Event from pretalx.submission.models import Submission from ...models import Rating, Score RATINGS_MIN = 30 SCALE = list(map(float, map(itemgetter(0), Rating.RATING_CHOICES))) MEAN = statistics.mean(SCALE) STD = math.sqrt(statistics.mean([(i - MEAN) ** 2 for i in SCALE])) class Command(BaseCommand): help = "Compute submission scores from ratings" def add_arguments(self, parser): parser.add_argument("event") def handle(self, *args, **kwargs): try: event = Event.objects.get(slug=kwargs["event"]) except Event.DoesNotExist: raise CommandError(f"no event found with slug '{kwargs['event']}'") with scope(event=event): submissions = {} for juror in event.jurors.prefetch_related("ratings"): ratings = { r.submission.code: int(r.rating) for r in juror.ratings.exclude(rating="") } values = list(ratings.values()) if len(values) < RATINGS_MIN: mean = MEAN std = STD else: mean = sum(values) / len(values) std = math.sqrt( sum([(i - mean) ** 2 for i in values]) / len(values) ) for code in ratings: if code not in submissions: submissions[code] = [] submissions[code].append((ratings[code] - mean) / std * STD + MEAN) for submission in Submission.objects.prefetch_related("score").filter( code__in=submissions.keys() ): try: score = submission.score except Submission.score.RelatedObjectDoesNotExist: score = Score(submission=submission) ratings = submissions[submission.code] score.value = sum(ratings) / len(ratings) score.save()