From 5174407da53a03e9e32d446c97c198ec2c16dd90 Mon Sep 17 00:00:00 2001 From: ngfchl Date: Fri, 3 Apr 2026 14:05:41 +0800 Subject: [PATCH] =?UTF-8?q?feat.=20=E6=B7=BB=E5=8A=A0=E6=96=87=E7=AB=A0?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=88=86=E9=A1=B5=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- article/schema.py | 62 +++++++++++++++++++++++++++++++++++++++++++++++ article/views.py | 36 ++++++++++++++++++--------- 2 files changed, 87 insertions(+), 11 deletions(-) create mode 100644 article/schema.py diff --git a/article/schema.py b/article/schema.py new file mode 100644 index 0000000..9f6c698 --- /dev/null +++ b/article/schema.py @@ -0,0 +1,62 @@ +from datetime import datetime +from typing import Optional, List, Generic, T + +from ninja import Schema +from pydantic import Field + + +# --- 假设的关联模型 Schema --- +class AuthorSchema(Schema): + id: int + username: str + + +class SectionSchema(Schema): + id: int + title: str # 假设 MainMenu 有 name 字段 + + +class AttachmentSchema(Schema): + id: int + file: str # 返回文件 URL 路径,如 "articles/attachments/2026/04/03/file.pdf" + + +class PaginatedResponseSchema(Schema, Generic[T]): + items: List[T] + total: int + page: int + per_page: int + total_pages: int + + +# --- Article 主 Schema --- +class ArticleSchema(Schema): + id: int + title: str + content: str + cover: Optional[str] = None # 图片 URL 路径 + is_contribution: bool + is_published: bool + created_at: datetime + updated_at: datetime + + # 关联字段 + author: Optional[AuthorSchema] = None + section: Optional[SectionSchema] = None + attachments: List[AttachmentSchema] = Field(default_factory=list) + + +# --- 创建文章用的 Schema (不含只读字段) --- +class ArticleCreateSchema(Schema): + title: str + section_id: Optional[int] = None # 外键通过 ID 传递 + content: str + cover: Optional[str] = None # 注意:文件上传通常需单独处理,此处仅为文本路径示例 + is_contribution: bool = False + is_published: bool = True + + +# --- 更新文章用的 Schema --- +class ArticleUpdateSchema(ArticleCreateSchema): + title: Optional[str] = None + content: Optional[str] = None diff --git a/article/views.py b/article/views.py index 9eb6c51..bf74a1e 100644 --- a/article/views.py +++ b/article/views.py @@ -1,10 +1,10 @@ -from django.http import HttpResponseForbidden -from django.shortcuts import render - -from article.models import Article -from utils.permission import user_has_permission +from typing import List from ninja import Router +from ninja.pagination import paginate, PageNumberPagination + +from article.models import Article +from article.schema import ArticleSchema, ArticleCreateSchema # Create your views here. @@ -12,9 +12,23 @@ from ninja import Router router = Router(tags=['content']) -@router.get('/article', description="获取文章列表") -def article_details(request): - if not user_has_permission(request.user, 'article', 'view'): - return HttpResponseForbidden("无权访问") - articles = Article.objects.all() - return render(request, 'articles/list.html', {'articles': articles}) +@router.get("/article", response=List[ArticleSchema], description="获取文章列表") +@paginate(PageNumberPagination, page_size=50) +def list_articles(request, ): + # 安全校验 per_page(防止过大 + queryset = Article.objects.prefetch_related('attachments').select_related('author', 'section') + return queryset + + +@router.post("/article", response=ArticleSchema) +def create_article(request, payload: ArticleCreateSchema): + # 注意:文件上传需额外处理(此处简化) + article = Article.objects.create( + title=payload.title, + section_id=payload.section_id, + author=request.auth, # 假设认证用户是作者 + content=payload.content, + is_contribution=payload.is_contribution, + is_published=payload.is_published, + ) + return article