From 3ac2cebffdeda2317ad9b5a23e634f186f876ebb Mon Sep 17 00:00:00 2001 From: Timur Date: Tue, 4 Mar 2025 06:13:38 +0300 Subject: [PATCH] add leaderboard view to admin panel --- services/backend/apps/competition/admin.py | 63 +++++++++++++++++++ services/backend/config/settings.py | 2 +- .../admin/competition_leaderboard.html | 43 +++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 services/backend/templates/admin/competition_leaderboard.html diff --git a/services/backend/apps/competition/admin.py b/services/backend/apps/competition/admin.py index a28901d..83bdebe 100644 --- a/services/backend/apps/competition/admin.py +++ b/services/backend/apps/competition/admin.py @@ -1,7 +1,15 @@ from django.contrib import admin +from django.urls import path, reverse +from django.http import HttpResponse +from django.template.response import TemplateResponse +from django.db.models import Count, Q, Sum +from django.shortcuts import get_object_or_404 +from django.utils.html import format_html +from apps.user.models import User from apps.competition.models import Competition from apps.task.admin import CompetitionTaskInline +from apps.task.models import CompetitionTaskSubmission, CompetitionTask @admin.register(Competition) @@ -11,6 +19,7 @@ class CompetitionAdmin(admin.ModelAdmin): "title", "end_date", "type", + "view_leaderboard", ) search_fields = ( "title", @@ -21,3 +30,57 @@ class CompetitionAdmin(admin.ModelAdmin): "participation_type", ) inlines = [CompetitionTaskInline] + + def get_urls(self): + urls = super().get_urls() + custom_urls = [ + path('leaderboard/', self.admin_site.admin_view(self.leaderboard_view), name='competition_leaderboard'), + path('/leaderboard/', self.admin_site.admin_view(self.competition_leaderboard_view), + name='competition_specific_leaderboard'), + ] + return custom_urls + urls + + def view_leaderboard(self, obj): + url = reverse('admin:competition_specific_leaderboard', args=[obj.id]) + return format_html('лидерборд', url) + + view_leaderboard.short_description = "Лидерборд" + view_leaderboard.allow_tags = True + + def competition_leaderboard_view(self, request, competition_id): + competition = get_object_or_404(Competition, id=competition_id) + + competition_tasks = CompetitionTask.objects.filter(competition=competition) + + leaderboard = User.objects.annotate( + total_score=Sum( + 'competitiontasksubmission__earned_points', + filter=Q( + competitiontasksubmission__status='checked', + competitiontasksubmission__task__in=competition_tasks + ) + ) + ).exclude(total_score__isnull=True).order_by('-total_score')[:20] + + context = dict( + self.admin_site.each_context(request), + title=f"Лидерборд для {competition.title}", + leaderboard=leaderboard, + competition=competition, + ) + return TemplateResponse(request, "admin/competition_leaderboard.html", context) + + def leaderboard_view(self, request): + leaderboard = User.objects.annotate( + total_score=Sum( + 'competitiontasksubmission__earned_points', + filter=Q(competitiontasksubmission__status='checked') + ) + ).exclude(total_score__isnull=True).order_by('-total_score')[:20] + + context = dict( + self.admin_site.each_context(request), + title="Global Competition Leaderboard", + leaderboard=leaderboard, + ) + return TemplateResponse(request, "admin/competition_leaderboard.html", context) diff --git a/services/backend/config/settings.py b/services/backend/config/settings.py index cb0d18e..5771663 100644 --- a/services/backend/config/settings.py +++ b/services/backend/config/settings.py @@ -552,7 +552,7 @@ SESSION_SERIALIZER = "django.contrib.sessions.serializers.JSONSerializer" TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [], + "DIRS": [BASE_DIR / "templates"], "APP_DIRS": True, "OPTIONS": { "autoescape": True, diff --git a/services/backend/templates/admin/competition_leaderboard.html b/services/backend/templates/admin/competition_leaderboard.html new file mode 100644 index 0000000..39d3cf7 --- /dev/null +++ b/services/backend/templates/admin/competition_leaderboard.html @@ -0,0 +1,43 @@ +{% extends "admin/base_site.html" %} +{% load i18n admin_urls %} + +{% block breadcrumbs %} + +{% endblock %} + +{% block content %} +
+

{% if competition %}Лидерборд: {{ competition.title }}{% else %}Лидерборд соревнования{% endif %}

+
+ + + + + + + + + + {% for user in leaderboard %} + + + + + + {% empty %} + + + + {% endfor %} + +
РангУчастникБаллы
{{ forloop.counter }}{{ user.username }}{{ user.total_score|default:0 }}
Пока что нет посылок
+
+
+{% endblock %} \ No newline at end of file