feat(problem): 新增批量给题目添加/移除标签接口
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -122,6 +122,12 @@ class EditTagSerializer(serializers.Serializer):
|
|||||||
name = serializers.CharField(max_length=32)
|
name = serializers.CharField(max_length=32)
|
||||||
|
|
||||||
|
|
||||||
|
class BatchProblemTagSerializer(serializers.Serializer):
|
||||||
|
problem_ids = serializers.ListField(child=serializers.IntegerField(), allow_empty=False)
|
||||||
|
tag_names = serializers.ListField(child=serializers.CharField(max_length=32), allow_empty=False)
|
||||||
|
action = serializers.ChoiceField(choices=["add", "remove"])
|
||||||
|
|
||||||
|
|
||||||
class BaseProblemSerializer(serializers.ModelSerializer):
|
class BaseProblemSerializer(serializers.ModelSerializer):
|
||||||
tags = serializers.SlugRelatedField(many=True, slug_field="name", read_only=True)
|
tags = serializers.SlugRelatedField(many=True, slug_field="name", read_only=True)
|
||||||
created_by = UsernameSerializer()
|
created_by = UsernameSerializer()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from django.urls import path
|
|||||||
|
|
||||||
from ..views.admin import (
|
from ..views.admin import (
|
||||||
AddContestProblemAPI,
|
AddContestProblemAPI,
|
||||||
|
BatchProblemTagAPI,
|
||||||
ContestProblemAPI,
|
ContestProblemAPI,
|
||||||
MakeContestProblemPublicAPIView,
|
MakeContestProblemPublicAPIView,
|
||||||
ProblemAPI,
|
ProblemAPI,
|
||||||
@@ -27,6 +28,7 @@ urlpatterns = [
|
|||||||
path("problem/top_ac_trend", TopACTrendAPI.as_view()),
|
path("problem/top_ac_trend", TopACTrendAPI.as_view()),
|
||||||
path("problem/flowchart", ProblemFlowchartAIGen.as_view()),
|
path("problem/flowchart", ProblemFlowchartAIGen.as_view()),
|
||||||
path("problem/tag", TagAdminAPI.as_view()),
|
path("problem/tag", TagAdminAPI.as_view()),
|
||||||
|
path("problem/batch_tag", BatchProblemTagAPI.as_view()),
|
||||||
path("contest/problem", ContestProblemAPI.as_view()),
|
path("contest/problem", ContestProblemAPI.as_view()),
|
||||||
path("contest_problem/make_public", MakeContestProblemPublicAPIView.as_view()),
|
path("contest_problem/make_public", MakeContestProblemPublicAPIView.as_view()),
|
||||||
path("contest/add_problem_from_public", AddContestProblemAPI.as_view()),
|
path("contest/add_problem_from_public", AddContestProblemAPI.as_view()),
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from utils.shortcuts import natural_sort_key, rand_str
|
|||||||
from ..models import Problem, ProblemTag
|
from ..models import Problem, ProblemTag
|
||||||
from ..serializers import (
|
from ..serializers import (
|
||||||
AddContestProblemSerializer,
|
AddContestProblemSerializer,
|
||||||
|
BatchProblemTagSerializer,
|
||||||
ContestProblemMakePublicSerializer,
|
ContestProblemMakePublicSerializer,
|
||||||
CreateContestProblemSerializer,
|
CreateContestProblemSerializer,
|
||||||
CreateProblemSerializer,
|
CreateProblemSerializer,
|
||||||
@@ -34,7 +35,7 @@ from ..serializers import (
|
|||||||
TagAdminSerializer,
|
TagAdminSerializer,
|
||||||
TestCaseUploadForm,
|
TestCaseUploadForm,
|
||||||
)
|
)
|
||||||
from ..services import clear_tag_cache, resolve_tags
|
from ..services import clear_tag_cache, find_tags, resolve_tags
|
||||||
from ..utils import generate_sql_display
|
from ..utils import generate_sql_display
|
||||||
|
|
||||||
|
|
||||||
@@ -554,6 +555,37 @@ class TagAdminAPI(APIView):
|
|||||||
return self.success()
|
return self.success()
|
||||||
|
|
||||||
|
|
||||||
|
class BatchProblemTagAPI(APIView):
|
||||||
|
@problem_permission_required
|
||||||
|
@validate_serializer(BatchProblemTagSerializer)
|
||||||
|
def post(self, request):
|
||||||
|
data = request.data
|
||||||
|
problems = Problem.objects.filter(id__in=data["problem_ids"], contest_id__isnull=True)
|
||||||
|
if not request.user.can_mgmt_all_problem():
|
||||||
|
problems = problems.filter(created_by=request.user)
|
||||||
|
problems = list(problems)
|
||||||
|
if not problems:
|
||||||
|
return self.error("没有可操作的题目")
|
||||||
|
|
||||||
|
# 添加时按需新建标签,移除时只认已有标签
|
||||||
|
if data["action"] == "add":
|
||||||
|
tags = resolve_tags(data["tag_names"])
|
||||||
|
else:
|
||||||
|
tags = find_tags(data["tag_names"])
|
||||||
|
if not tags:
|
||||||
|
return self.error("没有匹配的标签")
|
||||||
|
|
||||||
|
for problem in problems:
|
||||||
|
if data["action"] == "add":
|
||||||
|
problem.tags.add(*tags)
|
||||||
|
else:
|
||||||
|
problem.tags.remove(*tags)
|
||||||
|
|
||||||
|
# 题目数变化会影响前台标签列表(只展示 problem_count > 0 的)
|
||||||
|
clear_tag_cache()
|
||||||
|
return self.success({"problem_count": len(problems), "tag_count": len(tags)})
|
||||||
|
|
||||||
|
|
||||||
class ProblemVisibleAPI(APIView):
|
class ProblemVisibleAPI(APIView):
|
||||||
@problem_permission_required
|
@problem_permission_required
|
||||||
def put(self, request):
|
def put(self, request):
|
||||||
|
|||||||
Reference in New Issue
Block a user