From 776b470457ae6fed67753510eff04ceace97b522 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Thu, 6 Aug 2026 06:15:48 -0600 Subject: [PATCH] =?UTF-8?q?feat(reaction):=20=E8=AF=84=E4=BB=B7=E4=B8=80?= =?UTF-8?q?=E6=AC=A1=E5=AE=9A=E7=BB=88=E8=BA=AB=EF=BC=8C=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E5=90=8E=E4=B8=8D=E5=8F=AF=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 --- reaction/serializers.py | 2 +- reaction/views/oj.py | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/reaction/serializers.py b/reaction/serializers.py index edc234c..889408c 100644 --- a/reaction/serializers.py +++ b/reaction/serializers.py @@ -8,7 +8,7 @@ class SetReactionSerializer(serializers.Serializer): problem_id = serializers.IntegerField() types = serializers.ListField( child=serializers.ChoiceField(choices=ReactionType.choices), - allow_empty=True, + allow_empty=False, ) def validate_types(self, value): diff --git a/reaction/views/oj.py b/reaction/views/oj.py index b8246af..44d2642 100644 --- a/reaction/views/oj.py +++ b/reaction/views/oj.py @@ -1,5 +1,3 @@ -from asgiref.sync import sync_to_async -from django.db import transaction from django.db.models import Count, Q from account.decorators import login_required @@ -56,14 +54,15 @@ class ReactionAPI(AsyncAPIView): types = data["types"] user = request.user - def overwrite(): - with transaction.atomic(): - Reaction.objects.filter(user=user, problem=problem).delete() - Reaction.objects.bulk_create([Reaction(user=user, problem=problem, type=t) for t in types]) + # 评价一次定终身:已经评过的题不允许再改,避免统计被反复刷 + if await Reaction.objects.filter(user=user, problem=problem).aexists(): + return self.error("已经评价过了,不能修改") - await sync_to_async(overwrite)() + # ignore_conflicts 兜住并发重复提交,unique_together 保证不会写重 + await Reaction.objects.abulk_create( + [Reaction(user=user, problem=problem, type=t) for t in types], + ignore_conflicts=True, + ) await async_cache_delete(f"{CacheKey.reaction_stats}:{problem.id}") - if not types: - return self.success({"mine": [], "counts": None}) return self.success({"mine": types, "counts": await self.get_counts(problem.id)})