181 lines
5.4 KiB
Python
181 lines
5.4 KiB
Python
import os
|
||
import uuid
|
||
from datetime import datetime
|
||
from typing import Optional, List
|
||
|
||
from django.conf import settings
|
||
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 base.models import FriendLink, LinkCategory, PictureLink
|
||
from base.schema import FriendLinkCreateSchema, FriendLinkSchema, LinkCategoryCreateSchema, LinkCategorySchema, \
|
||
PictureLinkSchema, PictureLinkCreateSchema, PictureLinkUpdateSchema
|
||
|
||
# Create your views here.
|
||
router = Router(tags=['base'])
|
||
|
||
|
||
@csrf_exempt
|
||
@require_http_methods(["POST"])
|
||
def custom_upload_file(request):
|
||
"""
|
||
自定义 CKEditor 5 上传视图
|
||
支持:图片 + PDF / Word / Excel / ZIP 等所有文件
|
||
"""
|
||
file = request.FILES.get('upload')
|
||
if not file:
|
||
return JsonResponse({"error": "请选择文件"}, status=400)
|
||
|
||
# 安全处理文件名(避免中文/特殊字符报错)
|
||
ext = file.name.split('.')[-1].lower()
|
||
filename = f"{uuid.uuid4().hex}_{datetime.now().strftime('%Y%m%d%H%M%S')}.{ext}"
|
||
|
||
# 保存路径
|
||
upload_dir = os.path.join(settings.MEDIA_ROOT, 'uploads')
|
||
os.makedirs(upload_dir, exist_ok=True)
|
||
file_path = os.path.join(upload_dir, filename)
|
||
|
||
# 保存文件
|
||
with open(file_path, 'wb+') as f:
|
||
for chunk in file.chunks():
|
||
f.write(chunk)
|
||
|
||
# 返回文件 URL(CKEditor 规范格式)
|
||
file_url = f"{settings.MEDIA_URL}uploads/{filename}"
|
||
return JsonResponse({
|
||
"url": file_url,
|
||
"default": file_url
|
||
})
|
||
|
||
|
||
# =========================
|
||
# 分类 CRUD
|
||
# =========================
|
||
@router.get("/link-categories", response=List[LinkCategorySchema])
|
||
def list_categories(request):
|
||
return LinkCategory.objects.all()
|
||
|
||
|
||
@router.post("/link-categories", response=LinkCategorySchema)
|
||
def create_category(request, data: LinkCategoryCreateSchema):
|
||
return LinkCategory.objects.create(**data.dict())
|
||
|
||
|
||
@router.put("/link-categories/{id}", response=LinkCategorySchema)
|
||
def update_category(request, id: int, data: LinkCategoryCreateSchema):
|
||
obj = LinkCategory.objects.get(id=id)
|
||
for k, v in data.dict().items():
|
||
setattr(obj, k, v)
|
||
obj.save()
|
||
return obj
|
||
|
||
|
||
@router.delete("/link-categories/{id}")
|
||
def delete_category(request, id: int):
|
||
LinkCategory.objects.get(id=id).delete()
|
||
return {"success": True}
|
||
|
||
|
||
# =========================
|
||
# 友情链接 CRUD
|
||
# =========================
|
||
@router.get("/friend-links", response=List[FriendLinkSchema])
|
||
def list_links(request, category_id: Optional[int] = None):
|
||
query = FriendLink.objects.all()
|
||
if category_id:
|
||
query = query.filter(category_id=category_id)
|
||
return query
|
||
|
||
|
||
@router.post("/friend-links", response=FriendLinkSchema)
|
||
def create_link(request, data: FriendLinkCreateSchema):
|
||
return FriendLink.objects.create(**data.dict())
|
||
|
||
|
||
@router.put("/friend-links/{id}", response=FriendLinkSchema)
|
||
def update_link(request, id: int, data: FriendLinkCreateSchema):
|
||
obj = FriendLink.objects.get(id=id)
|
||
for k, v in data.dict().items():
|
||
setattr(obj, k, v)
|
||
obj.save()
|
||
return obj
|
||
|
||
|
||
@router.delete("/friend-links/{id}")
|
||
def delete_link(request, id: int):
|
||
FriendLink.objects.get(id=id).delete()
|
||
return {"success": True}
|
||
|
||
|
||
# ================= 列表与创建 =================
|
||
@router.get("/picture-link/", response=List[PictureLinkSchema])
|
||
def get_picture_links(request):
|
||
"""
|
||
获取所有图片链接
|
||
GET /api/picture-link/
|
||
"""
|
||
# 这里的排序与 models.py 中的 Meta.ordering 保持一致
|
||
return PictureLink.objects.all().order_by('order', '-created_at')
|
||
|
||
|
||
@router.post("/picture-link/", response=PictureLinkSchema)
|
||
def create_picture_link(request, payload: PictureLinkCreateSchema):
|
||
"""
|
||
新增图片链接
|
||
POST /api/picture-link/
|
||
"""
|
||
# 直接利用 payload 创建对象
|
||
# 注意:这里调用 save() 会触发你 models.py 中定义的 "最多4个启用" 的逻辑
|
||
link = PictureLink.objects.create(
|
||
name=payload.name,
|
||
picture=payload.picture,
|
||
url=payload.url,
|
||
order=payload.order,
|
||
is_active=payload.is_active
|
||
)
|
||
return link
|
||
|
||
|
||
# ================= 单个对象操作 =================
|
||
@router.get("/picture-link/{link_id}", response=PictureLinkSchema)
|
||
def get_picture_link(request, link_id: int):
|
||
"""
|
||
获取单个图片链接详情
|
||
GET /api/picture-link/{id}/
|
||
"""
|
||
return get_object_or_404(PictureLink, id=link_id)
|
||
|
||
|
||
@router.put("/picture-link/{link_id}", response=PictureLinkSchema)
|
||
def update_picture_link(request, link_id: int, payload: PictureLinkUpdateSchema):
|
||
"""
|
||
更新图片链接
|
||
PUT /api/picture-link/{id}/
|
||
"""
|
||
link = get_object_or_404(PictureLink, id=link_id)
|
||
|
||
# 更新字段
|
||
if payload.name is not None: link.name = payload.name
|
||
if payload.picture is not None: link.picture = payload.picture
|
||
if payload.url is not None: link.url = payload.url
|
||
if payload.order is not None: link.order = payload.order
|
||
if payload.is_active is not None: link.is_active = payload.is_active
|
||
|
||
# 保存,同样会触发 models.py 中的限制逻辑
|
||
link.save()
|
||
return link
|
||
|
||
|
||
@router.delete("/picture-link/{link_id}")
|
||
def delete_picture_link(request, link_id: int):
|
||
"""
|
||
删除图片链接
|
||
DELETE /api/picture-link/{id}/
|
||
"""
|
||
link = get_object_or_404(PictureLink, id=link_id)
|
||
link.delete()
|
||
return {"success": True}
|