feat: 新增 rebuild_sql_display 管理命令,为存量 SQL 题回填展示数据

生成逻辑从 ProblemBase._build_sql_display 提取为 problem.utils.generate_sql_display,
管理端保存与回填命令共用。命令支持 --dry-run / --force。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-03 09:42:11 -06:00
parent 5af9d67fe2
commit 2ec036ac37
5 changed files with 84 additions and 30 deletions

View File

@@ -0,0 +1,36 @@
from django.core.management.base import BaseCommand
from problem.models import Problem
from problem.utils import generate_sql_display
class Command(BaseCommand):
help = "为存量 SQL 题目重新生成 sql_display 展示数据(新建/编辑题目时会自动生成,此命令用于回填老题)"
def add_arguments(self, parser):
parser.add_argument("--dry-run", action="store_true", help="只检查并打印结果,不写数据库")
parser.add_argument("--force", action="store_true", help="已有 sql_display 的题目也重新生成(默认跳过)")
def handle(self, *args, **options):
qs = Problem.objects.filter(sql_config__isnull=False).order_by("id")
ok = failed = skipped = 0
for p in qs:
label = f"id={p.id} _id={p._id}" + (f" contest={p.contest_id}" if p.contest_id else "") + f" {p.title}"
if p.sql_display is not None and not options["force"]:
skipped += 1
self.stdout.write(f"SKIP {label}(已有 sql_display--force 可强制重建)")
continue
display, error = generate_sql_display(p.test_case_id, p.answers, p.sql_config)
if error:
failed += 1
self.stderr.write(self.style.ERROR(f"FAIL {label}: {error}"))
continue
if not options["dry_run"]:
p.sql_display = display
p.save(update_fields=["sql_display"])
ok += 1
self.stdout.write(self.style.SUCCESS(f"OK {label}"))
summary = f"完成:成功 {ok},失败 {failed},跳过 {skipped},共 {qs.count()} 道 SQL 题"
if options["dry_run"]:
summary += "dry-run未写库"
self.stdout.write(summary)