diff --git a/base/schema.py b/base/schema.py index 71cb3d3..f2766b4 100644 --- a/base/schema.py +++ b/base/schema.py @@ -101,3 +101,21 @@ class MainMenuOut(MainMenuBase): # 告诉 Pydantic 如何处理递归模型 MainMenuOut.model_rebuild() + + +class BaseInfoIn(Schema): + title: str + e_title: str + address: str + postal: Optional[str] = "" + telephone: Optional[str] = "" + fax: Optional[str] = "" + unit: Optional[str] = "" + filing: Optional[str] = "" + is_active: bool = False + + +class BaseInfoOut(BaseInfoIn): + id: int + official_account: Optional[str] = None + weibo: Optional[str] = None diff --git a/base/views.py b/base/views.py index 256b76c..51d13aa 100644 --- a/base/views.py +++ b/base/views.py @@ -1,6 +1,8 @@ +import hashlib import os import uuid from datetime import datetime +from pathlib import Path from typing import Optional, List from django.conf import settings @@ -8,11 +10,12 @@ from django.http import JsonResponse from django.shortcuts import get_object_or_404 from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_http_methods -from ninja import Router +from loguru import logger +from ninja import Router, UploadedFile, File +from ninja.pagination import paginate, PageNumberPagination -from base.models import FriendLink, LinkCategory, PictureLink, MainMenu -from base.schema import FriendLinkCreateSchema, FriendLinkSchema, LinkCategoryCreateSchema, LinkCategorySchema, \ - PictureLinkSchema, PictureLinkCreateSchema, PictureLinkUpdateSchema, MainMenuOut, MainMenuCreate, MainMenuUpdate +from base.models import FriendLink, LinkCategory, PictureLink, MainMenu, BaseInfo +from base.schema import * # Create your views here. router = Router(tags=['base']) @@ -51,6 +54,34 @@ def custom_upload_file(request): }) +UPLOAD_DIR = Path("media/uploads") +UPLOAD_DIR.mkdir(parents=True, exist_ok=True) + + +@router.post("/upload/") +def upload_file(request, upload: UploadedFile = File(...)): + try: + # 计算 md5 + md5 = hashlib.md5(upload.read()).hexdigest() + upload.seek(0) # 重置文件指针 + + ext = upload.name.split('.')[-1].lower() + filename = f"{md5}.{ext}" + + upload_dir = os.path.join(settings.MEDIA_ROOT, f"uploads/") + os.makedirs(upload_dir, exist_ok=True) + file_path = os.path.join(upload_dir, filename) + + with open(file_path, "wb") as f: + f.write(upload.read()) + + url = f"{settings.MEDIA_URL}uploads/{datetime.today().strftime('%Y/%m/%d')}/{filename}" + return {"url": url} + except Exception as e: + logger.exception("Upload failed") + return {"error": str(e)} + + # ========================= # 分类 CRUD # ========================= @@ -282,3 +313,47 @@ def delete_menu(request, menu_id: int): menu = get_object_or_404(MainMenu, id=menu_id) menu.delete() # Django 的级联删除会自动处理子项 return {"success": True} + + +# 查询列表 +@router.get("/base-info/", response=List[BaseInfoOut]) +@paginate(PageNumberPagination, page_size=20) +def list_base_info(request): + return BaseInfo.objects.all().order_by("-id") + + +# 获取详情 +@router.get("/base-info/{pk}", response=BaseInfoOut) +def get_base_info(request, pk: int): + return get_object_or_404(BaseInfo, pk=pk) + + +# 创建 +@router.post("/base-info/", response=BaseInfoOut) +def create_base_info(request, data: BaseInfoIn, ): + obj = BaseInfo.objects.create(**data.dict()) + return obj + + +# 更新 +@router.put("/base-info/{pk}", response=BaseInfoOut) +def update_base_info( + request, + pk: int, + data: BaseInfoIn, +): + obj = get_object_or_404(BaseInfo, pk=pk) + + for attr, value in data.dict().items(): + setattr(obj, attr, value) + + obj.save() + return obj + + +# 删除 +@router.delete("/base-info/{pk}") +def delete_base_info(request, pk: int): + obj = get_object_or_404(BaseInfo, pk=pk) + obj.delete() + return {"success": True}