From c0b7c294297b40557b2ad9d67ec9d962c9a03956 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Sun, 15 Jun 2025 14:41:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=87=AA=E5=AD=A6=E6=A8=A1?= =?UTF-8?q?=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- announcement/views/admin.py | 11 +- .../0002_tutorial_code_tutorial_type.py | 23 ++++ tutorial/models.py | 7 ++ tutorial/serializers.py | 53 ++++++++- tutorial/urls/admin.py | 16 +-- tutorial/urls/tutorial.py | 13 +-- tutorial/views/admin.py | 101 +++++++++++++++--- tutorial/views/oj.py | 23 ++++ tutorial/views/tutorial.py | 8 -- 9 files changed, 210 insertions(+), 45 deletions(-) create mode 100644 tutorial/migrations/0002_tutorial_code_tutorial_type.py create mode 100644 tutorial/views/oj.py delete mode 100644 tutorial/views/tutorial.py diff --git a/announcement/views/admin.py b/announcement/views/admin.py index 0fdaa3d..938ac3c 100644 --- a/announcement/views/admin.py +++ b/announcement/views/admin.py @@ -2,8 +2,11 @@ from account.decorators import super_admin_required from utils.api import APIView, validate_serializer from announcement.models import Announcement -from announcement.serializers import (AnnouncementSerializer, CreateAnnouncementSerializer, - EditAnnouncementSerializer) +from announcement.serializers import ( + AnnouncementSerializer, + CreateAnnouncementSerializer, + EditAnnouncementSerializer, +) class AnnouncementAdminAPI(APIView): @@ -50,7 +53,9 @@ class AnnouncementAdminAPI(APIView): announcement = Announcement.objects.all().order_by("-create_time") if request.GET.get("visible") == "true": announcement = announcement.filter(visible=True) - return self.success(self.paginate_data(request, announcement, AnnouncementSerializer)) + return self.success( + self.paginate_data(request, announcement, AnnouncementSerializer) + ) @super_admin_required def delete(self, request): diff --git a/tutorial/migrations/0002_tutorial_code_tutorial_type.py b/tutorial/migrations/0002_tutorial_code_tutorial_type.py new file mode 100644 index 0000000..c363cda --- /dev/null +++ b/tutorial/migrations/0002_tutorial_code_tutorial_type.py @@ -0,0 +1,23 @@ +# Generated by Django 5.2.3 on 2025-06-15 04:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tutorial', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='tutorial', + name='code', + field=models.TextField(default=''), + ), + migrations.AddField( + model_name='tutorial', + name='type', + field=models.CharField(choices=[('python', 'Python'), ('c', 'C')], default='python', max_length=10), + ), + ] diff --git a/tutorial/models.py b/tutorial/models.py index e9da6e3..f5e1881 100644 --- a/tutorial/models.py +++ b/tutorial/models.py @@ -2,8 +2,15 @@ from django.db import models from account.models import User class Tutorial(models.Model): + TYPE_CHOICES = [ + ('python', 'Python'), + ('c', 'C'), + ] + title = models.CharField(max_length=128) content = models.TextField() + code = models.TextField(default="") + type = models.CharField(max_length=10, choices=TYPE_CHOICES, default='python') created_by = models.ForeignKey(User, on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) diff --git a/tutorial/serializers.py b/tutorial/serializers.py index 86c6c77..df908c4 100644 --- a/tutorial/serializers.py +++ b/tutorial/serializers.py @@ -2,11 +2,54 @@ from rest_framework import serializers from .models import Tutorial from account.serializers import UserSerializer -class TutorialSerializer(serializers.ModelSerializer): + +class TutorialListSerializer(serializers.ModelSerializer): created_by = UserSerializer(read_only=True) - + class Meta: model = Tutorial - fields = ['id', 'title', 'content', 'created_by', 'created_at', - 'updated_at', 'is_public', 'order'] - read_only_fields = ['id', 'created_by', 'created_at', 'updated_at'] \ No newline at end of file + fields = [ + "id", + "title", + "created_by", + "created_at", + "updated_at", + "is_public", + "order", + "type", + ] + read_only_fields = ["id", "created_by", "created_at", "updated_at"] + + +class TutorialSerializer(serializers.ModelSerializer): + created_by = UserSerializer(read_only=True) + + class Meta: + model = Tutorial + fields = [ + "id", + "title", + "content", + "created_by", + "created_at", + "updated_at", + "is_public", + "order", + "type", + "code", + ] + read_only_fields = ["id", "created_by", "created_at", "updated_at"] + + +class CreateTutorialSerializer(serializers.ModelSerializer): + class Meta: + model = Tutorial + fields = ["title", "content", "is_public", "order", "type", "code"] + + +class EditTutorialSerializer(serializers.ModelSerializer): + id = serializers.IntegerField() + + class Meta: + model = Tutorial + fields = ["id", "title", "content", "is_public", "order", "type", "code"] diff --git a/tutorial/urls/admin.py b/tutorial/urls/admin.py index c23011b..8b6a047 100644 --- a/tutorial/urls/admin.py +++ b/tutorial/urls/admin.py @@ -1,10 +1,10 @@ -from django.urls import path, include -from rest_framework.routers import DefaultRouter -from ..views.admin import AdminTutorialViewSet - -router = DefaultRouter() -router.register(r'tutorials', AdminTutorialViewSet) +from django.urls import path +from ..views.admin import TutorialAdminAPI, TutorialVisibilityAPI urlpatterns = [ - path('', include(router.urls)), -] \ No newline at end of file + path("tutorial", TutorialAdminAPI.as_view()), + path( + "tutorial/visibility", + TutorialVisibilityAPI.as_view(), + ), +] diff --git a/tutorial/urls/tutorial.py b/tutorial/urls/tutorial.py index 1b3964b..e6c1476 100644 --- a/tutorial/urls/tutorial.py +++ b/tutorial/urls/tutorial.py @@ -1,10 +1,7 @@ -from django.urls import path, include -from rest_framework.routers import DefaultRouter -from ..views.tutorial import TutorialViewSet - -router = DefaultRouter() -router.register(r'tutorials', TutorialViewSet) +from django.urls import path +from ..views.oj import TutorialAPI, TutorialTitlesAPI urlpatterns = [ - path('', include(router.urls)), -] \ No newline at end of file + path("tutorial", TutorialAPI.as_view()), + path("tutorials", TutorialTitlesAPI.as_view()), +] diff --git a/tutorial/views/admin.py b/tutorial/views/admin.py index 23becf9..5f53d41 100644 --- a/tutorial/views/admin.py +++ b/tutorial/views/admin.py @@ -1,17 +1,92 @@ -from rest_framework import viewsets, permissions -from ..models import Tutorial -from ..serializers import TutorialSerializer +from account.decorators import super_admin_required +from utils.api import APIView, validate_serializer + +from tutorial.models import Tutorial +from tutorial.serializers import ( + TutorialSerializer, + TutorialListSerializer, + CreateTutorialSerializer, + EditTutorialSerializer, +) -class IsSuperAdminUser(permissions.BasePermission): - def has_permission(self, request, view): - return bool(request.user and request.user.is_super_admin()) +class TutorialAdminAPI(APIView): + @validate_serializer(CreateTutorialSerializer) + @super_admin_required + def post(self, request): + """ + create tutorial + """ + data = request.data + tutorial = Tutorial.objects.create(**data, created_by=request.user) + return self.success(TutorialSerializer(tutorial).data) + + @validate_serializer(EditTutorialSerializer) + @super_admin_required + def put(self, request): + """ + edit tutorial + """ + data = request.data + try: + tutorial = Tutorial.objects.get(id=data.pop("id")) + except Tutorial.DoesNotExist: + return self.error("Tutorial does not exist") + + for k, v in data.items(): + setattr(tutorial, k, v) + tutorial.save() + + return self.success(TutorialSerializer(tutorial).data) + + @super_admin_required + def get(self, request): + """ + get tutorial list / get one tutorial + """ + tutorial_id = request.GET.get("id") + if tutorial_id: + try: + tutorial = Tutorial.objects.get(id=tutorial_id) + return self.success(TutorialSerializer(tutorial).data) + except Tutorial.DoesNotExist: + return self.error("Tutorial does not exist") + + tutorials = Tutorial.objects.all().order_by("order", "-created_at") + # 按 type 分组返回数据 + result = { + "python": TutorialListSerializer( + tutorials.filter(type="python"), + many=True + ).data, + "c": TutorialListSerializer( + tutorials.filter(type="c"), + many=True + ).data + } + return self.success(result) + + @super_admin_required + def delete(self, request): + if request.GET.get("id"): + Tutorial.objects.filter(id=request.GET["id"]).delete() + return self.success() -class AdminTutorialViewSet(viewsets.ModelViewSet): - queryset = Tutorial.objects.all() - serializer_class = TutorialSerializer - permission_classes = [IsSuperAdminUser] - - def perform_create(self, serializer): - serializer.save(created_by=self.request.user) \ No newline at end of file +class TutorialVisibilityAPI(APIView): + @super_admin_required + def put(self, request): + """ + change tutorial visibility + """ + tutorial_id = request.data.get("id") + is_public = request.data.get("is_public") + if tutorial_id is None or is_public is None: + return self.error("Invalid parameter") + try: + tutorial = Tutorial.objects.get(id=tutorial_id) + except Tutorial.DoesNotExist: + return self.error("Tutorial does not exist") + tutorial.is_public = is_public + tutorial.save() + return self.success(TutorialSerializer(tutorial).data) diff --git a/tutorial/views/oj.py b/tutorial/views/oj.py new file mode 100644 index 0000000..4b828ea --- /dev/null +++ b/tutorial/views/oj.py @@ -0,0 +1,23 @@ +from utils.api import APIView + +from tutorial.models import Tutorial +from tutorial.serializers import TutorialSerializer + + +class TutorialAPI(APIView): + def get(self, request): + id = request.GET.get("id") + try: + tutorial = Tutorial.objects.get(id=id, is_public=True) + return self.success(TutorialSerializer(tutorial).data) + except Tutorial.DoesNotExist: + return self.error("Tutorial does not exist") + + +class TutorialTitlesAPI(APIView): + def get(self, request): + type = request.GET.get("type") or "python" + tutorials = Tutorial.objects.filter(is_public=True, type=type).values( + "id", "title" + ) + return self.success(list(tutorials)) diff --git a/tutorial/views/tutorial.py b/tutorial/views/tutorial.py deleted file mode 100644 index 2e4d5f8..0000000 --- a/tutorial/views/tutorial.py +++ /dev/null @@ -1,8 +0,0 @@ -from rest_framework import viewsets, permissions -from ..models import Tutorial -from ..serializers import TutorialSerializer - -class TutorialViewSet(viewsets.ReadOnlyModelViewSet): - queryset = Tutorial.objects.filter(is_public=True) - serializer_class = TutorialSerializer - permission_classes = [permissions.AllowAny] \ No newline at end of file