diff --git a/progress/management/commands/rebuild_leaderboard.py b/progress/management/commands/rebuild_leaderboard.py index ff33d86..1acd240 100644 --- a/progress/management/commands/rebuild_leaderboard.py +++ b/progress/management/commands/rebuild_leaderboard.py @@ -77,14 +77,8 @@ class Command(BaseCommand): from progress.models import LeaderboardEntry days = opts['days'] - scores = self._collect(period, days, include_zero=opts['include_zero']) - if not opts['include_zero']: - scores = [(uid, xp) for uid, xp in scores if xp > 0] - - # ترتیبِ قطعی: امتیازِ بیشتر جلوتر، و در تساوی user_id کوچک‌تر جلوتر — - # وگرنه دو اجرای پشت‌سرهم روی داده‌ی یکسان رتبه‌های متفاوت می‌دهند. - scores.sort(key=lambda p: (-p[1], p[0])) - scores = scores[:opts['limit']] + # مرتب‌سازی و کنار گذاشتنِ XPی صفر را خودِ compute_scores انجام می‌دهد. + scores = self._collect(period, days, include_zero=opts['include_zero'])[:opts['limit']] label = period if period == 'all_time' else f'{period} ({days} روزِ اخیر)' if opts['dry_run']: diff --git a/progress/views.py b/progress/views.py index ab5be36..bfb350c 100644 --- a/progress/views.py +++ b/progress/views.py @@ -7,7 +7,7 @@ from rest_framework.response import Response from rest_framework.throttling import ScopedRateThrottle from rest_framework.views import APIView -from .models import Character, LeaderboardEntry, StreakRecord, UserHearts, UserStats +from .models import Character, StreakRecord, UserHearts, UserStats from .services import effective_current_streak @@ -129,26 +129,22 @@ class LeaderboardView(APIView): scores = cache.get_or_set( f'leaderboard:{period}', lambda: compute_scores(period), LEADERBOARD_CACHE_TTL, ) - entries = [ - LeaderboardEntry(user_id=uid, period=period, xp_in_period=xp, rank=rank) - for rank, (uid, xp) in enumerate(scores, 1) - ] - # نام کاربر از accounts.User خونده می‌شه (فقط برای نمایش، بدون FK واقعی). from accounts.models import User as AccountUser - user_ids = [e.user_id for e in entries] - names = {u.id: u.name for u in AccountUser.objects.filter(id__in=user_ids)} + names = dict( + AccountUser.objects.filter(id__in=[uid for uid, _ in scores]).values_list('id', 'name') + ) data = { 'period': period, 'entries': [ { - 'rank': e.rank, - 'userId': str(e.user_id), - 'name': names.get(e.user_id, ''), - 'xpInPeriod': e.xp_in_period, + 'rank': rank, + 'userId': str(uid), + 'name': names.get(uid, ''), + 'xpInPeriod': xp, } - for e in entries + for rank, (uid, xp) in enumerate(scores, 1) ], } return Response(LeaderboardResponseSerializer(data).data)