76 lines
1.9 KiB
Python
76 lines
1.9 KiB
Python
|
|
from typing import List, Optional
|
|||
|
|
|
|||
|
|
from pydantic import BaseModel, Field
|
|||
|
|
|
|||
|
|
from app.models.domain.articles import Article
|
|||
|
|
from app.models.schemas.rwschema import RWSchema
|
|||
|
|
|
|||
|
|
DEFAULT_ARTICLES_LIMIT = 20
|
|||
|
|
DEFAULT_ARTICLES_OFFSET = 0
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ArticleForResponse(RWSchema, Article):
|
|||
|
|
"""
|
|||
|
|
返回给前端的文章结构:
|
|||
|
|
- 继承 Article(包含 cover、tags、author 等)
|
|||
|
|
- tags 字段通过 alias 暴露为 tagList,兼容前端
|
|||
|
|
"""
|
|||
|
|
tags: List[str] = Field(..., alias="tagList")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ArticleInResponse(RWSchema):
|
|||
|
|
article: ArticleForResponse
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ArticleInCreate(RWSchema):
|
|||
|
|
"""
|
|||
|
|
创建文章时请求体:
|
|||
|
|
{
|
|||
|
|
"article": {
|
|||
|
|
"title": "...",
|
|||
|
|
"description": "...",
|
|||
|
|
"body": "...",
|
|||
|
|
"tagList": ["..."],
|
|||
|
|
"cover": "可选封面URL"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
"""
|
|||
|
|
title: str
|
|||
|
|
description: str
|
|||
|
|
body: str
|
|||
|
|
tags: List[str] = Field([], alias="tagList")
|
|||
|
|
cover: Optional[str] = None
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ArticleInUpdate(RWSchema):
|
|||
|
|
"""
|
|||
|
|
更新文章时请求体(全部可选):
|
|||
|
|
- 不传的字段不改
|
|||
|
|
- cover:
|
|||
|
|
- 不传:不改
|
|||
|
|
- 传 null / "":清空封面(配合 repo 的 cover_provided 使用)
|
|||
|
|
- 传字符串:更新为新封面
|
|||
|
|
"""
|
|||
|
|
title: Optional[str] = None
|
|||
|
|
description: Optional[str] = None
|
|||
|
|
body: Optional[str] = None
|
|||
|
|
cover: Optional[str] = None
|
|||
|
|
is_top: Optional[bool] = None
|
|||
|
|
is_featured: Optional[bool] = None
|
|||
|
|
sort_weight: Optional[int] = None
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ListOfArticlesInResponse(RWSchema):
|
|||
|
|
articles: List[ArticleForResponse]
|
|||
|
|
articles_count: int
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ArticlesFilters(BaseModel):
|
|||
|
|
tag: Optional[str] = None
|
|||
|
|
tags: Optional[List[str]] = None
|
|||
|
|
author: Optional[str] = None
|
|||
|
|
favorited: Optional[str] = None
|
|||
|
|
search: Optional[str] = None
|
|||
|
|
limit: int = Field(DEFAULT_ARTICLES_LIMIT, ge=1)
|
|||
|
|
offset: int = Field(DEFAULT_ARTICLES_OFFSET, ge=0)
|