From 1504164ae8167c59c8f8a2f599c0ab64cb94a1a8 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Tue, 4 Aug 2026 09:50:19 -0600 Subject: [PATCH] =?UTF-8?q?fix(achievement):=20distinct()=20=E5=89=8D?= =?UTF-8?q?=E5=BF=85=E9=A1=BB=20order=5Fby()=20=E6=B8=85=E6=8E=89=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Submission.Meta 有 ordering=("-create_time",),Django 会把排序字段 并入 DISTINCT,导致 _languages 每条提交各成一行——生产环境实测 某用户 659 条而不是 5 种语言。 recompute 侥幸正确只因 .count() 会清排序,两个实现同一个量却不一致。 三处 distinct() 全部显式加 order_by()。 由 check_achievement_deploy 的自检项发现。 Co-Authored-By: Claude Opus 5 --- achievement/metrics.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/achievement/metrics.py b/achievement/metrics.py index 235d589..6a59a72 100644 --- a/achievement/metrics.py +++ b/achievement/metrics.py @@ -103,7 +103,7 @@ class AcceptedCount(BaseMetric): metrics["accepted_count"] = metrics.get("accepted_count", 0) + 1 def recompute(self, user): - return _practice_submissions(user.id).filter(result__in=ACCEPTED_RESULTS).values("problem_id").distinct().count() + return _practice_submissions(user.id).filter(result__in=ACCEPTED_RESULTS).order_by().values("problem_id").distinct().count() @metric("submission_count", "提交总数", "提交次数(不含比赛)") @@ -181,10 +181,14 @@ class LanguagesUsed(BaseMetric): metrics["languages_used"] = len(seen) def recompute(self, user): - return _practice_submissions(user.id).values("language").distinct().count() + return _practice_submissions(user.id).order_by().values("language").distinct().count() def recompute_state(self, user): - return {"_languages": list(_practice_submissions(user.id).values_list("language", flat=True).distinct())} + # order_by() 不能省:Submission.Meta 有默认排序 ("-create_time",), + # Django 会把排序字段并入 DISTINCT,于是每条提交各成一行—— + # 实测某用户返回 659 条而不是 5 种语言。 + # recompute 侥幸正确只是因为 .count() 会清掉排序,不能依赖这一点。 + return {"_languages": list(_practice_submissions(user.id).order_by().values_list("language", flat=True).distinct())} @metric("contest_joined", "参赛场次", "参加过的比赛数量(本指标是比赛维度,不受比赛提交不计入的限制)") @@ -194,7 +198,7 @@ class ContestJoined(BaseMetric): return def recompute(self, user): - return Submission.objects.filter(user_id=user.id, contest_id__isnull=False).values("contest_id").distinct().count() + return Submission.objects.filter(user_id=user.id, contest_id__isnull=False).order_by().values("contest_id").distinct().count() @metric("badge_count", "题单奖章数", "获得的题单奖章数量")