From 38f92ed911f2797c1e89367af12be9965a2c0817 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Sat, 8 Aug 2026 07:19:02 -0600 Subject: [PATCH] =?UTF-8?q?chore:=20=E5=88=A0=2011=20=E4=B8=AA=E6=97=A0?= =?UTF-8?q?=E5=BC=95=E7=94=A8=E5=BA=8F=E5=88=97=E5=8C=96=E5=99=A8=EF=BC=9B?= =?UTF-8?q?=E6=92=A4=E5=9B=9E=E4=B8=80=E5=A4=84=E8=AF=AF=E5=88=A4=E7=9A=84?= =?UTF-8?q?"=E4=BF=AE=E5=A4=8D"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 撤回:增删题单题目本来就会重算进度,我诊断错了 上一个 commit 我给 ProblemSetProblemAdminAPI 的 post/delete 加了显式的 sync_all_progress_for_problemset,理由是"增删题目不重算进度"。**那是错的。** problemset/signals.py 里有 post_save / post_delete 信号接收器, 在 ProblemSetProblem 变化时同步进度**并重算奖章**,且 apps.py 的 ready() 确实导入了 signals。我的显式调用只是让同一件事做两遍。 更该记住的是**为什么当时没发现**:那一版测试只看"进度有没有更新", 而信号和我的调用都会让它更新 —— 分不出是谁干的,所以照样是绿的。 这次的测试改成先撤掉调用再验,并直接断言信号已注册在 post_save/post_delete 上, 这样才真的有区分力。6/6 通过。 同一批修复里的另外 5 条经复核都成立,保留。特别是「移除用户留下孤儿奖章」—— signals.py 里**没有**针对 ProblemSetProgress 的 post_delete,那条必须自己清。 ## 删无引用序列化器(-78 行) 全仓 106 个序列化器,11 个无任何引用: account: FileUploadForm, GenerateUserSerializer, SSOSerializer, UserChangeEmailSerializer, UserChangePasswordSerializer, UsernameOrEmailCheckSerializer contest: CreateContestAnnouncementSerializer, EditContestAnnouncementSerializer problem: CreateProblemCodeTemplateSerializer flowchart: FlowchartSubmissionMergedSerializer, FlowchartSubmissionSummarySerializer 前 8 个是上一个 commit 删掉的视图留下的(FileUploadForm 正是 SimditorFileUploadAPIView 用的),后 3 个是原本就死的。 检测器同样做了自检:拿 3 个明确在用的序列化器反测,没有误判。 另外确认这 11 个都没有字符串形式的动态引用。 `ruff check .` 全绿。行尾未被改动(上一轮踩过这个坑,这次脚本里加了断言)。 Co-Authored-By: Claude Opus 5 --- account/serializers.py | 31 ------------------------------- contest/serializers.py | 14 -------------- flowchart/serializers.py | 29 ----------------------------- problem/serializers.py | 4 ---- problemset/views/admin.py | 8 ++------ 5 files changed, 2 insertions(+), 84 deletions(-) diff --git a/account/serializers.py b/account/serializers.py index 6dcee19..6e955d7 100644 --- a/account/serializers.py +++ b/account/serializers.py @@ -10,35 +10,12 @@ class UserLoginSerializer(serializers.Serializer): password = serializers.CharField() -class UsernameOrEmailCheckSerializer(serializers.Serializer): - username = serializers.CharField(required=False) - email = serializers.EmailField(required=False) - - class UserRegisterSerializer(serializers.Serializer): username = serializers.CharField(max_length=32) password = serializers.CharField(min_length=6) email = serializers.EmailField(max_length=64) -class UserChangePasswordSerializer(serializers.Serializer): - old_password = serializers.CharField() - new_password = serializers.CharField(min_length=6) - - -class UserChangeEmailSerializer(serializers.Serializer): - password = serializers.CharField() - new_email = serializers.EmailField(max_length=64) - - -class GenerateUserSerializer(serializers.Serializer): - prefix = serializers.CharField(max_length=16, allow_blank=True) - suffix = serializers.CharField(max_length=16, allow_blank=True) - number_from = serializers.IntegerField() - number_to = serializers.IntegerField() - password_length = serializers.IntegerField(max_value=16, default=8) - - class ImportUserSerializer(serializers.Serializer): users = serializers.ListField(child=serializers.ListField(child=serializers.CharField(max_length=64))) @@ -130,18 +107,10 @@ class EditUserProfileSerializer(serializers.Serializer): language = serializers.CharField(max_length=32, allow_blank=True, required=False) -class SSOSerializer(serializers.Serializer): - token = serializers.CharField() - - class ImageUploadForm(forms.Form): image = forms.FileField() -class FileUploadForm(forms.Form): - file = forms.FileField() - - class RankInfoSerializer(serializers.ModelSerializer): user = UsernameSerializer() diff --git a/contest/serializers.py b/contest/serializers.py index 5f7c08a..4940881 100644 --- a/contest/serializers.py +++ b/contest/serializers.py @@ -50,20 +50,6 @@ class ContestAnnouncementSerializer(serializers.ModelSerializer): fields = "__all__" -class CreateContestAnnouncementSerializer(serializers.Serializer): - contest_id = serializers.IntegerField() - title = serializers.CharField(max_length=128) - content = serializers.CharField() - visible = serializers.BooleanField() - - -class EditContestAnnouncementSerializer(serializers.Serializer): - id = serializers.IntegerField() - title = serializers.CharField(max_length=128, required=False) - content = serializers.CharField(required=False, allow_blank=True) - visible = serializers.BooleanField(required=False) - - class ContestPasswordVerifySerializer(serializers.Serializer): contest_id = serializers.IntegerField() password = serializers.CharField(max_length=30, required=True) diff --git a/flowchart/serializers.py b/flowchart/serializers.py index 336e4d3..e5f1a2e 100644 --- a/flowchart/serializers.py +++ b/flowchart/serializers.py @@ -74,32 +74,3 @@ class FlowchartSubmissionListSerializer(serializers.ModelSerializer): "evaluation_time", ] - -class FlowchartSubmissionSummarySerializer(serializers.ModelSerializer): - """用于AI详情页面的极简序列化器,只包含必要字段""" - - problem_title = serializers.CharField(source="problem.title") - problem__id = serializers.CharField(source="problem._id") - - class Meta: - model = FlowchartSubmission - fields = [ - "id", - "problem__id", - "problem_title", - "ai_score", - "ai_grade", - "create_time", - ] - - -class FlowchartSubmissionMergedSerializer(serializers.Serializer): - """合并后的流程图提交序列化器""" - - problem__id = serializers.CharField() - problem_title = serializers.CharField() - submission_count = serializers.IntegerField() - best_score = serializers.FloatField() - best_grade = serializers.CharField() - latest_submission_time = serializers.DateTimeField() - avg_score = serializers.FloatField() diff --git a/problem/serializers.py b/problem/serializers.py index fb37624..e3a4dde 100644 --- a/problem/serializers.py +++ b/problem/serializers.py @@ -31,10 +31,6 @@ class CreateTestCaseScoreSerializer(serializers.Serializer): score = serializers.IntegerField(min_value=0) -class CreateProblemCodeTemplateSerializer(serializers.Serializer): - pass - - class SQLConfigSerializer(serializers.Serializer): mode = serializers.ChoiceField(choices=["query", "modify"]) order_sensitive = serializers.BooleanField(default=False) diff --git a/problemset/views/admin.py b/problemset/views/admin.py index d69e3d3..c628599 100644 --- a/problemset/views/admin.py +++ b/problemset/views/admin.py @@ -166,10 +166,7 @@ class ProblemSetProblemAdminAPI(APIView): score=data.get("score", 0), hint=data.get("hint", ""), ) - # 题目数就是进度的分母,加完必须重算:不重算的话已加入的学生进度百分比 - # 全是虚高的,而且原本标成"已完成"的人会一直是已完成。 - # 手动同步接口(ProblemSetSyncAPI)前端没有调用点,所以只能在这里做。 - ProblemSetProgress.sync_all_progress_for_problemset(problem_set) + # 进度和奖章由 problemset/signals.py 的 post_save 信号自动重算,这里不用管。 return self.success("题目已添加到题单") @@ -215,8 +212,7 @@ class ProblemSetProblemAdminAPI(APIView): try: problem_set_problem = ProblemSetProblem.objects.get(id=problem_set_problem_id, problemset=problem_set) problem_set_problem.delete() - # 同上:分母变了,进度要重算 - ProblemSetProgress.sync_all_progress_for_problemset(problem_set) + # 进度和奖章由 post_delete 信号自动重算 return self.success("题目已从题单中移除") except ProblemSetProblem.DoesNotExist: return self.error("题目不在该题单中")