重构数据

This commit is contained in:
2025-03-07 00:06:56 +08:00
parent 317f29b486
commit c95dafe14d
32 changed files with 219 additions and 215 deletions

0
task/__init__.py Normal file
View File

5
task/admin.py Normal file
View File

@@ -0,0 +1,5 @@
from django.contrib import admin
from .models import Tutorial, Challenge
admin.site.register(Tutorial)
admin.site.register(Challenge)

7
task/apps.py Normal file
View File

@@ -0,0 +1,7 @@
from django.apps import AppConfig
class TaskConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "task"
verbose_name = "任务"

View File

@@ -0,0 +1,58 @@
# Generated by Django 5.1.6 on 2025-03-06 16:03
import django.db.models.deletion
import django_extensions.db.fields
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Task',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True, verbose_name='created')),
('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True, verbose_name='modified')),
('display', models.IntegerField(unique=True)),
('title', models.CharField(max_length=100)),
('content', models.TextField()),
('task_type', models.CharField(choices=[('challenge', 'Challenge'), ('tutorial', 'Tutorial')], editable=False, max_length=20)),
('is_public', models.BooleanField(default=False)),
],
options={
'get_latest_by': 'modified',
'abstract': False,
},
),
migrations.CreateModel(
name='Challenge',
fields=[
('task_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='task.task')),
('score', models.IntegerField(default=0)),
],
options={
'verbose_name': '挑战',
'verbose_name_plural': '挑战',
'ordering': ('display',),
},
bases=('task.task',),
),
migrations.CreateModel(
name='Tutorial',
fields=[
('task_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='task.task')),
],
options={
'verbose_name': '教程',
'verbose_name_plural': '教程',
'ordering': ('display',),
},
bases=('task.task',),
),
]

View File

46
task/models.py Normal file
View File

@@ -0,0 +1,46 @@
from django.db import models
from django_extensions.db.models import TimeStampedModel
class Task(TimeStampedModel):
TASK_TYPE_CHOICES = [
("challenge", "Challenge"),
("tutorial", "Tutorial"),
]
display = models.IntegerField(unique=True)
title = models.CharField(max_length=100)
content = models.TextField()
task_type = models.CharField(
max_length=20,
choices=TASK_TYPE_CHOICES,
editable=False,
)
is_public = models.BooleanField(default=False)
def save(self, *args, **kwargs):
if not self.task_type:
self.task_type = self.__class__.__name__.lower()
super().save(*args, **kwargs)
class Tutorial(Task):
def __str__(self):
return self.title
class Meta:
ordering = ("display",)
verbose_name = "教程"
verbose_name_plural = verbose_name
class Challenge(Task):
score = models.IntegerField(default=0)
def __str__(self):
return self.title
class Meta:
ordering = ("display",)
verbose_name = "挑战"
verbose_name_plural = verbose_name

21
task/schemas.py Normal file
View File

@@ -0,0 +1,21 @@
from ninja import Schema, ModelSchema
from .models import Tutorial
class TutorialSlim(Schema):
display: int
title: str
is_public: bool
class TutorialAll(ModelSchema):
class Meta:
model = Tutorial
fields = "__all__"
class TutorialIn(Schema):
display: int
title: str
content: str
is_public: bool = False

62
task/tutorial.py Normal file
View File

@@ -0,0 +1,62 @@
from typing import List
from ninja import Router
from ninja.errors import HttpError
from account.decorators import super_required
from .schemas import TutorialAll, TutorialIn, TutorialSlim
from .models import Tutorial
router = Router()
@router.get("/list", response=List[TutorialSlim])
@super_required
def tutorial(request):
return Tutorial.objects.all()
@router.get("/display", response=List[int])
def get_all_public_display(request):
return Tutorial.objects.filter(is_public=True).values_list("display", flat=True)
@router.get("/{display}", response=TutorialAll)
def get(request, display: int):
try:
return Tutorial.objects.get(display=display)
except Tutorial.DoesNotExist:
raise HttpError(404, "此序号无教程")
@router.post("/")
@super_required
def create_or_update(request, payload: TutorialIn):
try:
item = Tutorial.objects.get(display=payload.display)
item.title = payload.title
item.content = payload.content
item.is_public = payload.is_public
item.save()
return {"message": "更新成功"}
except Tutorial.DoesNotExist:
Tutorial.objects.create(**payload.dict())
return {"message": "创建成功"}
@router.put("/public/{display}")
@super_required
def toggle_public(request, display: int):
try:
item = Tutorial.objects.get(display=display)
item.is_public = not item.is_public
item.save()
label = "公开" if item.is_public else "隐藏"
return {"message": f"{item.display}{item.title}{label}"}
except Tutorial.DoesNotExist:
raise HttpError(404, "此序号无教程")
@router.delete("/{display}")
@super_required
def remove(request, display: int):
Tutorial.objects.filter(display=display).delete()
return {"message": "删除成功"}