Skip to content

Commit

Permalink
Improve APIv2
Browse files Browse the repository at this point in the history
- Sort all list endpoints by ID, which reduces the likelihood of objects
  moving between pages during requests. Objects will only shift if an
  object is deleted, which usually does not happen.
- Add a list filter for ID (and other identifier fields), so users can
  request a list of only the objects they care about (rather than
  requesting all and then filtering on their side)
- Use the rating from Profile.rating instead of re-computing it each
  time. This attribute should already be updated during each contest
  rate.
Ninjaclasher authored and Xyene committed Dec 25, 2023
1 parent 2035e60 commit 6baf5c3
Showing 1 changed file with 19 additions and 13 deletions.
32 changes: 19 additions & 13 deletions judge/views/api/api_v2.py
Original file line number Diff line number Diff line change
@@ -199,6 +199,7 @@ class APIContestList(APIListView):
('is_rated', 'is_rated'),
)
list_filters = (
('key', 'key'),
('tag', 'tags__name'),
('organization', 'organizations'),
)
@@ -213,7 +214,7 @@ def get_unfiltered_queryset(self):
to_attr='tag_list',
),
)
.order_by('end_time')
.order_by('id')
)

def get_object_data(self, contest):
@@ -393,6 +394,7 @@ class APIProblemList(APIListView):
('partial', 'partial'),
)
list_filters = (
('code', 'code'),
('group', 'group__full_name'),
('type', 'types__full_name'),
('organization', 'organizations'),
@@ -409,7 +411,7 @@ def get_unfiltered_queryset(self):
to_attr='type_list',
),
)
.order_by('code')
.order_by('id')
.distinct()
)

@@ -478,20 +480,18 @@ def get_object_data(self, problem):
class APIUserList(APIListView):
model = Profile
list_filters = (
('id', 'id'),
('username', 'username'),
('organization', 'organizations'),
)

def get_unfiltered_queryset(self):
latest_rating_subquery = Rating.objects.filter(user=OuterRef('pk')).order_by('-contest__end_time')
return (
Profile.objects
.filter(is_unlisted=False, user__is_active=True)
.annotate(
username=F('user__username'),
latest_rating=Subquery(latest_rating_subquery.values('rating')[:1]),
)
.annotate(username=F('user__username'))
.order_by('id')
.only('id', 'points', 'performance_points', 'problem_count', 'display_rank')
.only('id', 'points', 'performance_points', 'problem_count', 'display_rank', 'rating')
)

def get_object_data(self, profile):
@@ -502,7 +502,7 @@ def get_object_data(self, profile):
'performance_points': profile.performance_points,
'problem_count': profile.problem_count,
'rank': profile.display_rank,
'rating': profile.latest_rating,
'rating': profile.rating,
}


@@ -524,8 +524,6 @@ def get_object_data(self, profile):
.values_list('problem__code', flat=True),
)

last_rating = profile.ratings.order_by('-contest__end_time').first()

contest_history = []
participations = (
ContestParticipation.objects
@@ -557,7 +555,7 @@ def get_object_data(self, profile):
'problem_count': profile.problem_count,
'solved_problems': solved_problems,
'rank': profile.display_rank,
'rating': last_rating.rating if last_rating is not None else None,
'rating': profile.rating,
'organizations': list(profile.organizations.values_list('id', flat=True)),
'contests': contest_history,
}
@@ -570,6 +568,7 @@ class APISubmissionList(APIListView):
('problem', ProblemSimpleFilter('problem')),
)
list_filters = (
('id', 'id'),
('language', LanguageListFilter('language')),
('result', 'result'),
)
@@ -681,6 +680,9 @@ class APIOrganizationList(APIListView):
basic_filters = (
('is_open', 'is_open'),
)
list_filters = (
('id', 'id'),
)

def get_unfiltered_queryset(self):
return Organization.objects.annotate(member_count=Count('member')).order_by('id')
@@ -700,6 +702,10 @@ class APILanguageList(APIListView):
basic_filters = (
('common_name', 'common_name'),
)
list_filters = (
('id', 'id'),
('key', 'key'),
)

def get_object_data(self, language):
return {
@@ -717,7 +723,7 @@ class APIJudgeList(APIListView):
model = Judge

def get_unfiltered_queryset(self):
return Judge.objects.filter(online=True).prefetch_related('runtimes').order_by('name')
return Judge.objects.filter(online=True).prefetch_related('runtimes').order_by('id')

def get_object_data(self, judge):
return {

0 comments on commit 6baf5c3

Please sign in to comment.