Contest caching
This commit is contained in:
parent
86d1ff4eaa
commit
571596dcbf
9 changed files with 72 additions and 23 deletions
|
@ -299,6 +299,18 @@ class ContestAdmin(CompareVersionAdmin):
|
|||
self._rescore(obj.key)
|
||||
self._rescored = True
|
||||
|
||||
if form.changed_data and any(
|
||||
f in form.changed_data
|
||||
for f in (
|
||||
"authors",
|
||||
"curators",
|
||||
"testers",
|
||||
)
|
||||
):
|
||||
Contest._author_ids.dirty(obj)
|
||||
Contest._curator_ids.dirty(obj)
|
||||
Contest._tester_ids.dirty(obj)
|
||||
|
||||
def save_related(self, request, form, formsets, change):
|
||||
super().save_related(request, form, formsets, change)
|
||||
# Only rescored if we did not already do so in `save_model`
|
||||
|
|
|
@ -25,6 +25,7 @@ from judge.ratings import rate_contest
|
|||
from judge.models.pagevote import PageVotable
|
||||
from judge.models.bookmark import Bookmarkable
|
||||
from judge.fulltext import SearchManager
|
||||
from judge.caching import cache_wrapper
|
||||
|
||||
__all__ = [
|
||||
"Contest",
|
||||
|
@ -455,25 +456,41 @@ class Contest(models.Model, PageVotable, Bookmarkable):
|
|||
def ended(self):
|
||||
return self.end_time < self._now
|
||||
|
||||
@cached_property
|
||||
def author_ids(self):
|
||||
return Contest.authors.through.objects.filter(contest=self).values_list(
|
||||
@cache_wrapper(prefix="Coai")
|
||||
def _author_ids(self):
|
||||
return set(
|
||||
Contest.authors.through.objects.filter(contest=self).values_list(
|
||||
"profile_id", flat=True
|
||||
)
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def editor_ids(self):
|
||||
return self.author_ids.union(
|
||||
@cache_wrapper(prefix="Coci")
|
||||
def _curator_ids(self):
|
||||
return set(
|
||||
Contest.curators.through.objects.filter(contest=self).values_list(
|
||||
"profile_id", flat=True
|
||||
)
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def tester_ids(self):
|
||||
return Contest.testers.through.objects.filter(contest=self).values_list(
|
||||
@cache_wrapper(prefix="Coti")
|
||||
def _tester_ids(self):
|
||||
return set(
|
||||
Contest.testers.through.objects.filter(contest=self).values_list(
|
||||
"profile_id", flat=True
|
||||
)
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def author_ids(self):
|
||||
return self._author_ids()
|
||||
|
||||
@cached_property
|
||||
def editor_ids(self):
|
||||
return self.author_ids.union(self._curator_ids())
|
||||
|
||||
@cached_property
|
||||
def tester_ids(self):
|
||||
return self._tester_ids()
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.key})"
|
||||
|
|
|
@ -116,7 +116,7 @@ def infinite_paginate(queryset, page, page_size, pad_pages, paginator=None):
|
|||
|
||||
|
||||
class InfinitePaginationMixin:
|
||||
pad_pages = 4
|
||||
pad_pages = 2
|
||||
|
||||
@property
|
||||
def use_infinite_pagination(self):
|
||||
|
|
|
@ -198,7 +198,7 @@ class ContestList(
|
|||
queryset = (
|
||||
super(ContestList, self)
|
||||
.get_queryset()
|
||||
.prefetch_related("tags", "organizations", "authors", "curators", "testers")
|
||||
.prefetch_related("tags", "organizations")
|
||||
)
|
||||
|
||||
if self.request.GET.get("contest"):
|
||||
|
@ -248,9 +248,6 @@ class ContestList(
|
|||
virtual=0, user=self.request.profile, contest_id__in=present
|
||||
)
|
||||
.select_related("contest")
|
||||
.prefetch_related(
|
||||
"contest__authors", "contest__curators", "contest__testers"
|
||||
)
|
||||
.annotate(key=F("contest__key"))
|
||||
):
|
||||
if not participation.ended:
|
||||
|
|
|
@ -478,6 +478,9 @@ class OrganizationSubmissions(
|
|||
),
|
||||
)
|
||||
|
||||
def get_title(self):
|
||||
return _("Submissions in") + f" {self.organization}"
|
||||
|
||||
|
||||
class OrganizationMembershipChange(
|
||||
LoginRequiredMixin, OrganizationMixin, SingleObjectMixin, View
|
||||
|
@ -983,6 +986,18 @@ class EditOrganizationContest(
|
|||
)
|
||||
):
|
||||
transaction.on_commit(rescore_contest.s(self.object.key).delay)
|
||||
|
||||
if any(
|
||||
f in form.changed_data
|
||||
for f in (
|
||||
"authors",
|
||||
"curators",
|
||||
"testers",
|
||||
)
|
||||
):
|
||||
Contest._author_ids.dirty(self.object)
|
||||
Contest._curator_ids.dirty(self.object)
|
||||
Contest._tester_ids.dirty(self.object)
|
||||
return res
|
||||
|
||||
def get_problem_formset(self, post=False):
|
||||
|
@ -1075,7 +1090,7 @@ class EditOrganizationBlog(
|
|||
if self.organization not in self.blog.organizations.all():
|
||||
raise Exception("This blog does not belong to this organization")
|
||||
if (
|
||||
self.request.profile not in self.blog.authors.all()
|
||||
self.request.profile.id not in self.blog.get_authors()
|
||||
and not self.can_edit_organization(self.organization)
|
||||
):
|
||||
raise Exception("Not allowed to edit this blog")
|
||||
|
|
|
@ -64,6 +64,7 @@ from judge.models import (
|
|||
Organization,
|
||||
Profile,
|
||||
LanguageTemplate,
|
||||
Contest,
|
||||
)
|
||||
from judge.pdf_problems import DefaultPdfMaker, HAS_PDF
|
||||
from judge.utils.diggpaginator import DiggPaginator
|
||||
|
@ -587,7 +588,7 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
|
|||
i
|
||||
for i in query
|
||||
if i in self.profile.organizations.values_list("id", flat=True)
|
||||
]
|
||||
][:3]
|
||||
|
||||
def get_normal_queryset(self):
|
||||
queryset = Problem.get_visible_problems(self.request.user)
|
||||
|
@ -599,9 +600,14 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
|
|||
self.org_query = [self.request.organization.id]
|
||||
if self.org_query:
|
||||
self.org_query = self.get_org_query(self.org_query)
|
||||
contest_problems = (
|
||||
Contest.objects.filter(organizations__in=self.org_query)
|
||||
.select_related("problems")
|
||||
.values_list("contest_problems__problem__id")
|
||||
.distinct()
|
||||
)
|
||||
queryset = queryset.filter(
|
||||
Q(organizations__in=self.org_query)
|
||||
| Q(contests__contest__organizations__in=self.org_query)
|
||||
Q(organizations__in=self.org_query) | Q(id__in=contest_problems)
|
||||
)
|
||||
if self.author_query:
|
||||
queryset = queryset.filter(authors__in=self.author_query)
|
||||
|
|
|
@ -52,7 +52,7 @@ from judge.utils.timedelta import nice_repr
|
|||
def submission_related(queryset):
|
||||
return queryset.select_related("user", "problem", "language").only(
|
||||
"id",
|
||||
"user_id",
|
||||
"user__id",
|
||||
"problem__name",
|
||||
"problem__code",
|
||||
"problem__is_public",
|
||||
|
@ -67,7 +67,8 @@ def submission_related(queryset):
|
|||
"case_points",
|
||||
"case_total",
|
||||
"current_testcase",
|
||||
"contest_object",
|
||||
"contest_object__key",
|
||||
"contest_object__name",
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ ul.problem-list {
|
|||
|
||||
.organization-tags {
|
||||
padding-left: 0.75em;
|
||||
vertical-align: middle;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.organization-tag {
|
||||
|
@ -183,6 +183,7 @@ ul.problem-list {
|
|||
position: relative;
|
||||
background-color: #ccc;
|
||||
color: initial;
|
||||
min-height: 1.5em;
|
||||
}
|
||||
|
||||
.organization-tag a {
|
||||
|
|
|
@ -193,7 +193,7 @@
|
|||
{% macro contest_join(contest, request) %}
|
||||
{% if request.in_contest and request.participation.contest == contest %}
|
||||
<button class="small" disabled>{{ _('In contest') }}</button>
|
||||
{% elif request.profile in contest.authors.all() or request.profile in contest.curators.all() or request.profile in contest.testers.all() %}
|
||||
{% elif request.profile.id in contest.editor_ids or request.profile.id in contest.tester_ids %}
|
||||
<form action="{{ url('contest_join', contest.key) }}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="unselectable button full small"
|
||||
|
|
Loading…
Reference in a new issue