""" 文章 CRUD 操作 """ from datetime import datetime from typing import Optional, List, Tuple from app.models.post import Post, PostTag from app.models.user import User from app.models.category import Category from app.models.tag import Tag class PostCRUD: """文章 CRUD 操作类""" @staticmethod async def get_by_id(post_id: str) -> Optional[Post]: """根据 ID 获取文章""" return await Post.filter(id=post_id).first() @staticmethod async def get_by_slug(slug: str) -> Optional[Post]: """根据 slug 获取文章""" return await Post.filter(slug=slug).first() @staticmethod async def get_all( page: int = 1, page_size: int = 10, status: str = "published", category_id: Optional[str] = None, tag_id: Optional[str] = None ) -> Tuple[List[Post], int]: """获取文章列表(分页)""" query = Post.all() if status: query = query.filter(status=status) if category_id: query = query.filter(category_id=category_id) if tag_id: query = query.filter(tags__id=tag_id) total = await query.count() posts = await query \ .prefetch_related("author", "category", "tags") \ .offset((page - 1) * page_size) \ .limit(page_size) \ .order_by("-created_at") return posts, total @staticmethod async def get_by_author( author_id: str, page: int = 1, page_size: int = 10 ) -> Tuple[List[Post], int]: """获取指定作者的文章列表""" query = Post.filter(author_id=author_id) total = await query.count() posts = await query \ .prefetch_related("author", "category", "tags") \ .offset((page - 1) * page_size) \ .limit(page_size) \ .order_by("-created_at") return posts, total @staticmethod async def create( title: str, slug: str, content: str, author_id: str, summary: Optional[str] = None, cover_image: Optional[str] = None, category_id: Optional[str] = None, tag_ids: Optional[List[str]] = None, status: str = "draft", meta_title: Optional[str] = None, meta_description: Optional[str] = None ) -> Post: """创建文章""" post = await Post.create( title=title, slug=slug, content=content, author_id=author_id, summary=summary, cover_image=cover_image, category_id=category_id, status=status, meta_title=meta_title, meta_description=meta_description ) # 添加标签 if tag_ids: for tag_id in tag_ids: await PostTag.create(post_id=post.id, tag_id=tag_id) return post @staticmethod async def update(post_id: str, **kwargs) -> Optional[Post]: """更新文章""" post = await Post.filter(id=post_id).first() if not post: return None # 处理标签更新 if "tag_ids" in kwargs: tag_ids = kwargs.pop("tag_ids") # 删除旧标签关联 await PostTag.filter(post_id=post_id).delete() # 添加新标签关联 for tag_id in tag_ids: await PostTag.create(post_id=post_id, tag_id=tag_id) # 处理发布状态更新 if kwargs.get("status") == "published" and not post.published_at: kwargs["published_at"] = datetime.utcnow() for key, value in kwargs.items(): if value is not None and hasattr(post, key): setattr(post, key, value) await post.save() return post @staticmethod async def delete(post_id: str) -> bool: """删除文章""" post = await Post.filter(id=post_id).first() if post: await post.delete() return True return False @staticmethod async def increment_view_count(post_id: str) -> None: """增加浏览量""" await Post.filter(id=post_id).update(view_count=Post.view_count + 1) @staticmethod async def get_hot_posts(limit: int = 10) -> List[Post]: """获取热门文章(按浏览量排序)""" return await Post.filter(status="published") \ .prefetch_related("author", "category") \ .order_by("-view_count") \ .limit(limit) @staticmethod async def get_recent_posts(limit: int = 10) -> List[Post]: """获取最新文章""" return await Post.filter(status="published") \ .prefetch_related("author", "category", "tags") \ .order_by("-created_at") \ .limit(limit) post_crud = PostCRUD()