From 8ecfeb5e36b787bf03cc7952f00f90cc44e2f3f2 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Tue, 4 Aug 2026 04:40:17 -0600 Subject: [PATCH] =?UTF-8?q?fix(problemset):=20=E5=A5=96=E7=AB=A0=E5=88=A4?= =?UTF-8?q?=E5=AE=9A=E4=BF=AE=E5=A4=8D=20N+1=20=E4=B8=8E=E5=B9=B6=E5=8F=91?= =?UTF-8?q?=E5=86=B2=E7=AA=81=E5=B9=B6=E6=8E=A5=E5=85=A5=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problemset/views/oj.py | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/problemset/views/oj.py b/problemset/views/oj.py index d704cc2..70b45d6 100644 --- a/problemset/views/oj.py +++ b/problemset/views/oj.py @@ -3,6 +3,7 @@ from django.utils import timezone from account.decorators import login_required, teacher_admin_required from account.models import User +from achievement.notify import notify_badges from problem.models import Problem from problemset.models import ( BadgeConditionType, @@ -229,22 +230,39 @@ class ProblemSetProgressAPI(APIView): return self.success("进度已更新") def _check_badges(self, progress): - """检查是否获得奖章""" - badges = ProblemSetBadge.objects.filter(problemset=progress.problemset) + """检查是否获得奖章。 + 一次查询取出全部已获奖章 id,内存比对,避免逐条 exists()(原来的 N+1)。 + 用 get_or_create 避免并发重复提交撞 unique constraint 抛异常。 + 新获得的奖章推送给用户——接入前奖章是静默入库的,学生根本不知道自己拿到了。 + """ + badges = list(ProblemSetBadge.objects.filter(problemset=progress.problemset)) + if not badges: + return + + owned = set(UserBadge.objects.filter(user=progress.user, badge__in=badges).values_list("badge_id", flat=True)) + + earned = [] for badge in badges: - if UserBadge.objects.filter(user=progress.user, badge=badge).exists(): + if badge.id in owned: continue if badge.condition_type == BadgeConditionType.ALL_PROBLEMS: - if progress.total_problems_count > 0 and progress.completed_problems_count == progress.total_problems_count: - UserBadge.objects.create(user=progress.user, badge=badge) + hit = progress.total_problems_count > 0 and progress.completed_problems_count == progress.total_problems_count elif badge.condition_type == BadgeConditionType.PROBLEM_COUNT: - if progress.completed_problems_count >= badge.condition_value: - UserBadge.objects.create(user=progress.user, badge=badge) + hit = progress.completed_problems_count >= badge.condition_value elif badge.condition_type == BadgeConditionType.SCORE: - if progress.total_score >= badge.condition_value: - UserBadge.objects.create(user=progress.user, badge=badge) + hit = progress.total_score >= badge.condition_value + else: + hit = False + + if hit: + _, created = UserBadge.objects.get_or_create(user=progress.user, badge=badge) + if created: + earned.append(badge) + + if earned: + notify_badges(progress.user_id, earned) # DEPRECATED: 前端未调用 (2026-05-26)