from django.core.management.base import BaseCommand from problemset.models import ProblemSetProblem, ProblemSetProgress, ProblemSetSubmission from submission.models import JudgeStatus, Submission class Command(BaseCommand): help = "根据实际提交记录修复题单进度数据" def add_arguments(self, parser): parser.add_argument("--problemset-id", type=int, help="只修复指定题单(不传则修复全部)") parser.add_argument("--dry-run", action="store_true", help="只检查,不写入数据库") def handle(self, *args, **options): dry_run = options["dry_run"] problemset_id = options.get("problemset_id") progresses = ProblemSetProgress.objects.select_related("user", "problemset") if problemset_id: progresses = progresses.filter(problemset_id=problemset_id) total = progresses.count() self.stdout.write(f"共检查 {total} 条进度记录{'(dry-run 模式)' if dry_run else ''}") fixed_count = 0 for progress in progresses: problemset_problems = ProblemSetProblem.objects.filter( problemset=progress.problemset ).select_related("problem") updated = False for psp in problemset_problems: problem_id = str(psp.problem_id) if problem_id in progress.progress_detail: continue accepted = ( Submission.objects.filter( user_id=progress.user_id, problem_id=psp.problem_id, result__in=[JudgeStatus.ACCEPTED, JudgeStatus.AST_CHECK_FAILED], ) .order_by("create_time") .first() ) if not accepted: continue self.stdout.write( f" 用户 {progress.user.username} | 题单「{progress.problemset.title}」" f" | 题目 {psp.problem._id} 已AC但进度未记录" ) if dry_run: continue progress.progress_detail[problem_id] = { "score": psp.score, "submit_time": accepted.create_time.isoformat(), } if not ProblemSetSubmission.objects.filter( problemset=progress.problemset, user=progress.user, problem=psp.problem, ).exists(): ProblemSetSubmission.objects.create( problemset=progress.problemset, user=progress.user, submission=accepted, problem=psp.problem, ) updated = True if updated: progress.update_progress() fixed_count += 1 if dry_run: self.stdout.write(self.style.WARNING("dry-run 完成,未写入任何数据")) else: self.stdout.write(self.style.SUCCESS(f"修复完成,共更新 {fixed_count} 条进度记录"))