first commit
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
from pydantic import BaseModel, Field, ValidationError, model_validator
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Optional, TypeVar, Generic, List
|
||||
from pydantic import BaseModel, Field, model_serializer
|
||||
|
||||
class BaseResponseWithID(BaseModel):
|
||||
"""
|
||||
Mixin: 统一处理输入中的 id/_id -> id
|
||||
约束:
|
||||
- 若 id 与 _id 同时出现且值不同 -> 报错
|
||||
- 若仅 _id 出现 -> 转成 id
|
||||
- 若两者都缺失 -> 报错
|
||||
- 最终保证存在 id: str
|
||||
"""
|
||||
id: str = Field(..., description="资源唯一标识ID")
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def normalize_id(cls, data: Any) -> Any:
|
||||
# 仅处理 dict-like 输入;其他情况交给 Pydantic 默认流程
|
||||
if not isinstance(data, dict):
|
||||
return data
|
||||
|
||||
has_id = "id" in data
|
||||
has__id = "_id" in data
|
||||
|
||||
if has_id and has__id:
|
||||
if str(data["id"]) != str(data["_id"]):
|
||||
raise ValidationError([
|
||||
{
|
||||
"type": "value_error",
|
||||
"loc": ("id",),
|
||||
"msg": "id and _id both provided but not equal",
|
||||
"input": data.get("id"),
|
||||
}
|
||||
], cls)
|
||||
# 相同则优先保留 id,去掉 _id
|
||||
data = {**data}
|
||||
data.pop("_id", None)
|
||||
return data
|
||||
|
||||
if has__id and not has_id:
|
||||
# 将 _id 统一映射为 id
|
||||
data = {**data}
|
||||
data["id"] = str(data["_id"])
|
||||
data.pop("_id", None)
|
||||
return data
|
||||
|
||||
if not has_id and not has__id:
|
||||
raise ValidationError([
|
||||
{
|
||||
"type": "value_error.missing",
|
||||
"loc": ("id",),
|
||||
"msg": "id or _id is required",
|
||||
"input": data,
|
||||
}
|
||||
], cls)
|
||||
|
||||
# 默认返回(已有 id)
|
||||
return data
|
||||
|
||||
class RequestApprovalMixin(BaseModel):
|
||||
"""
|
||||
请求审批相关的基础模型
|
||||
"""
|
||||
pass
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
# def _build_full_response_dict(code: int, message: Optional[str], data: Any) -> dict:
|
||||
# """构建与 __orjson__ 完全一致的响应字典"""
|
||||
# # 处理 data 的序列化(与 __orjson__ 逻辑同步)
|
||||
# if data is None:
|
||||
# clean_data = {}
|
||||
# elif isinstance(data, BaseModel):
|
||||
# clean_data = data.model_dump()
|
||||
# else:
|
||||
# clean_data = data
|
||||
# return {
|
||||
# "code": code,
|
||||
# "message": message,
|
||||
# "data": clean_data
|
||||
# }
|
||||
|
||||
class Success(BaseModel, Generic[T]):
|
||||
code: int = 200
|
||||
message: Optional[str] = "OK"
|
||||
data: Optional[T] = None
|
||||
|
||||
# def __init__(self, **kwargs):
|
||||
# super().__init__(**kwargs)
|
||||
# # 自动捕获完整响应结构到 push_log.result
|
||||
# push_log = current_push_log.get()
|
||||
# if push_log is not None:
|
||||
# full_response = _build_full_response_dict(self.code, self.message, self.data)
|
||||
# push_log.result = full_response
|
||||
#
|
||||
class Fail(BaseModel):
|
||||
code: int = 400
|
||||
message: Optional[str] = None
|
||||
data: Optional[Any] = Field(default_factory=dict)
|
||||
|
||||
class PaginatedList(BaseModel, Generic[T]):
|
||||
list: List[T] = Field(default_factory=list)
|
||||
total: int = 0
|
||||
page: int = 1
|
||||
page_size: int = 20
|
||||
Reference in New Issue
Block a user