From 0539afd7a198d39c55f851ed5f2680c1e4cc9ad1 Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 11 Mar 2024 02:45:42 -0400 Subject: [PATCH] Remove gaps. (lil sketchy) --- gameserver/models/cache.py | 21 +++++++++++++-------- gameserver/models/contest.py | 22 ++++++++++++++-------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/gameserver/models/cache.py b/gameserver/models/cache.py index a6ca1e2..8d8bfc0 100644 --- a/gameserver/models/cache.py +++ b/gameserver/models/cache.py @@ -1,14 +1,12 @@ from typing import TYPE_CHECKING, Self, Optional from django.apps import apps -from django.contrib.auth.models import Permission -from django.contrib.contenttypes.models import ContentType from django.db import models, transaction -from django.db.models import Count, F, Sum, Window, Value, When, BooleanField, Case, Q -from django.db.models.functions import Coalesce, Rank +from django.db.models import Count, F, Sum, Window, Value, When, BooleanField, Case, Q, OuterRef, Subquery +from django.db.models.functions import Coalesce, Rank, DenseRank, RowNumber +from .contest import Contest, ContestParticipation, ContestSubmission if TYPE_CHECKING: - from .contest import Contest, ContestParticipation from .profile import User @@ -111,6 +109,8 @@ def ranks(cls, contest: "Contest", queryset: Optional[models.QuerySet] = None, p # perm_edit_all_contests = Permission.objects.get( # codename="edit_all_contests", content_type=contest_content_type # ) + max_submission_time_subquery = ContestSubmission.objects.filter( + participation=OuterRef('participation')).order_by('-submission__date_created').values('submission__date_created')[:1] query = cls.objects.filter(participation__contest=contest).prefetch_related("participation")#.exclude( # Q(participants__is_superuser=True) # | Q(participants__groups__permissions=perm_edit_all_contests) @@ -122,11 +122,16 @@ def ranks(cls, contest: "Contest", queryset: Optional[models.QuerySet] = None, p When(participation__team_id=None, then=Value(False)), default=Value(True), output_field=BooleanField()), - rank=Window( + sub_rank=Window( expression=Rank(), order_by=F("points").desc(), - ) - ).order_by("rank", "flag_count") + ), + rank=Window( + expression=RowNumber(), + order_by=F("points").desc(), + ), + max_submission_time=Subquery(max_submission_time_subquery) + ).order_by("rank", "flag_count", "-max_submission_time") if queryset is not None: data = data.filter(participation__in=queryset) return data diff --git a/gameserver/models/contest.py b/gameserver/models/contest.py index db99e86..53f3167 100644 --- a/gameserver/models/contest.py +++ b/gameserver/models/contest.py @@ -1,5 +1,6 @@ from datetime import timedelta +from django.apps import apps from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType from django.core.cache import cache @@ -14,10 +15,8 @@ from django.utils.functional import cached_property from . import abstract -from .cache import ContestScore from ..templatetags.common_tags import strfdelta - # Create your models here. @@ -26,6 +25,10 @@ class ContestTag(abstract.Category): class Contest(models.Model): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.ContestScore = apps.get_model("gameserver", "ContestScore", require_ready=True) + organizers = models.ManyToManyField("User", related_name="contests_organized", blank=True) curators = models.ManyToManyField("User", related_name="contests_curated", blank=True) organizations = models.ManyToManyField("Organization", related_name="contests", blank=True) @@ -94,7 +97,7 @@ def __meta_key(self): return f"contest_ranks_{self.pk}" def ranks(self, queryset=None): - return ContestScore.ranks(self) + return self.ContestScore.ranks(self) def _ranks(self, queryset=None): if queryset is None: @@ -224,6 +227,10 @@ def get_editable_contests(cls, user): class ContestParticipation(models.Model): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.ContestScore = apps.get_model("gameserver", "ContestScore", require_ready=True) + contest = models.ForeignKey(Contest, on_delete=models.CASCADE, related_name="participations") is_disqualified = models.BooleanField(default=False) @@ -260,15 +267,14 @@ def _get_unique_correct_submissions(self): ) def points(self): - return ContestScore.objects.filter(participation=self).values_list("points", flat=True).get() + + return self.ContestScore.objects.filter(participation=self).values_list("points", flat=True).get() def flags(self): - return ContestScore.objects.filter(participation=self).values_list("flag_count", flat=True).get() + return self.ContestScore.objects.filter(participation=self).values_list("flag_count", flat=True).get() def get_rank(self): - print("GETTING RANK", flush=True) - print(ContestScore.ranks(self.contest, participation=self), "RANKS") - return ContestScore.ranks(self.contest, participation=self) + return self.ContestScore.ranks(self.contest, participation=self) @cached_property def last_solve(self): submissions = (