feat(mixin): add TableBaseMixin and UUIDTableBaseMixin for async CRUD operations

- Implemented TableBaseMixin providing generic CRUD methods and automatic timestamp management.
- Introduced UUIDTableBaseMixin for models using UUID as primary keys.
- Added ListResponse for standardized paginated responses.
- Created TimeFilterRequest and PaginationRequest for filtering and pagination parameters.
- Enhanced get_with_count method to return both item list and total count.
- Included validation for time filter parameters in TimeFilterRequest.
- Improved documentation and usage examples throughout the code.
This commit is contained in:
2025-12-22 18:29:14 +08:00
parent 47a4756227
commit a5efda9c23
44 changed files with 4306 additions and 497 deletions

View File

@@ -1,11 +1,12 @@
from datetime import datetime
from enum import StrEnum
from typing import Literal, Optional, TYPE_CHECKING
from typing import Literal, TYPE_CHECKING
from uuid import UUID
from sqlmodel import Field, Relationship
from .base import SQLModelBase, UUIDTableBase
from .base import SQLModelBase
from .mixin import UUIDTableBaseMixin
if TYPE_CHECKING:
from .group import Group
@@ -19,15 +20,6 @@ if TYPE_CHECKING:
from .user_authn import UserAuthn
from .webdav import WebDAV
"""
Option 需求
- 主题 跟随系统/浅色/深色
- 颜色方案 参考 ThemeResponse
- 语言
- 时区
- 切换到不同存储策略是否提醒
"""
class AvatarType(StrEnum):
"""头像类型枚举"""
@@ -42,6 +34,13 @@ class ThemeType(StrEnum):
DARK = "dark"
SYSTEM = "system"
class UserStatus(StrEnum):
"""用户状态枚举"""
ACTIVE = "active"
ADMIN_BANNED = "admin_banned"
SYSTEM_BANNED = "system_banned"
# ==================== Base 模型 ====================
@@ -51,8 +50,8 @@ class UserBase(SQLModelBase):
username: str
"""用户名"""
status: bool = True
"""用户状态: True=正常, False=封禁"""
status: UserStatus = UserStatus.ACTIVE
"""用户状态"""
score: int = 0
"""用户积分"""
@@ -72,7 +71,7 @@ class LoginRequest(SQLModelBase):
captcha: str | None = None
"""验证码"""
two_fa_code: str | None = None
two_fa_code: int | None = Field(min_length=6, max_length=6)
"""两步验证代码"""
@@ -192,9 +191,6 @@ class UserSettingResponse(SQLModelBase):
prefer_theme: str = "#5898d4"
"""用户首选主题"""
qq: str | None = None
"""QQ号"""
themes: dict[str, str] = {}
"""用户主题配置"""
@@ -216,7 +212,7 @@ UserSettingResponse.model_rebuild()
# ==================== 数据库模型 ====================
class User(UserBase, UUIDTableBase, table=True):
class User(UserBase, UUIDTableBaseMixin):
"""用户模型"""
username: str = Field(max_length=50, unique=True, index=True)
@@ -243,7 +239,7 @@ class User(UserBase, UUIDTableBase, table=True):
score: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, ge=0)
"""用户积分"""
group_expires: datetime | None = None
group_expires: datetime | None = Field(default=None)
"""当前用户组过期时间"""
# Option 相关字段
@@ -266,13 +262,13 @@ class User(UserBase, UUIDTableBase, table=True):
# 关系
group: "Group" = Relationship(
back_populates="user",
back_populates="users",
sa_relationship_kwargs={
"foreign_keys": "User.group_id"
}
)
previous_group: Optional["Group"] = Relationship(
back_populates="previous_user",
previous_group: "Group" = Relationship(
back_populates="previous_users",
sa_relationship_kwargs={
"foreign_keys": "User.previous_group_id"
}