mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-21 20:55:14 +00:00
chore: update .gitignore and enhance docstrings across multiple files
- Added *.pyc and *.pyo to .gitignore to prevent compiled Python files from being tracked. - Improved docstrings in various modules, providing clearer descriptions of functions, parameters, and return values to enhance code readability and maintainability.
This commit is contained in:
@@ -42,6 +42,7 @@ async def login_for_access_token_controller(
|
||||
|
||||
参数:
|
||||
- request (Request): FastAPI请求对象
|
||||
- redis (Redis): Redis 客户端对象
|
||||
- login_form (CustomOAuth2PasswordRequestForm): 登录表单数据
|
||||
- db (AsyncSession): 数据库会话对象
|
||||
|
||||
@@ -82,6 +83,8 @@ async def get_new_token_controller(
|
||||
参数:
|
||||
- request (Request): FastAPI请求对象
|
||||
- payload (RefreshTokenPayloadSchema): 刷新令牌负载模型
|
||||
- db (AsyncSession): 数据库会话对象
|
||||
- redis (Redis): Redis 客户端对象
|
||||
|
||||
返回:
|
||||
- JWTOutSchema: 包含新的访问令牌和刷新令牌的响应模型
|
||||
|
||||
@@ -25,6 +25,15 @@ class JWTPayloadSchema(BaseModel):
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_fields(self):
|
||||
"""
|
||||
校验 JWT 载荷字段的基本合法性。
|
||||
|
||||
返回:
|
||||
- JWTPayloadSchema: 校验后的载荷实例。
|
||||
|
||||
异常:
|
||||
- ValueError: 必填字段为空或格式不正确时抛出。
|
||||
"""
|
||||
if not self.sub or len(self.sub.strip()) == 0:
|
||||
raise ValueError("会话编号不能为空")
|
||||
return self
|
||||
|
||||
@@ -11,7 +11,15 @@ class DeptCRUD(CRUDBase[DeptModel, DeptCreateSchema, DeptUpdateSchema]):
|
||||
"""部门模块数据层"""
|
||||
|
||||
def __init__(self, auth: AuthSchema) -> None:
|
||||
"""初始化部门CRUD"""
|
||||
"""
|
||||
初始化部门数据层。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型(含 DB 会话等上下文)。
|
||||
|
||||
返回:
|
||||
- None
|
||||
"""
|
||||
self.auth = auth
|
||||
super().__init__(model=DeptModel, auth=auth)
|
||||
|
||||
|
||||
@@ -22,6 +22,18 @@ class DeptCreateSchema(BaseModel):
|
||||
@field_validator("name")
|
||||
@classmethod
|
||||
def validate_name(cls, value: str):
|
||||
"""
|
||||
校验并规范化部门名称(去空格、非空)。
|
||||
|
||||
参数:
|
||||
- value (str): 部门名称。
|
||||
|
||||
返回:
|
||||
- str: 规范化后的部门名称。
|
||||
|
||||
异常:
|
||||
- ValueError: 部门名称为空时抛出。
|
||||
"""
|
||||
if not value or len(value.strip()) == 0:
|
||||
raise ValueError("部门名称不能为空")
|
||||
value = value.replace(" ", "")
|
||||
@@ -30,6 +42,18 @@ class DeptCreateSchema(BaseModel):
|
||||
@field_validator("code")
|
||||
@classmethod
|
||||
def validate_code(cls, value: str | None):
|
||||
"""
|
||||
校验部门编码:字母开头,仅包含字母/数字/下划线;空字符串视为 None。
|
||||
|
||||
参数:
|
||||
- value (str | None): 部门编码。
|
||||
|
||||
返回:
|
||||
- str | None: 规范化后的部门编码或 None。
|
||||
|
||||
异常:
|
||||
- ValueError: 编码不满足格式要求时抛出。
|
||||
"""
|
||||
if value is None:
|
||||
return value
|
||||
v = value.strip()
|
||||
|
||||
@@ -126,7 +126,7 @@ class DeptService:
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证对象。
|
||||
- ids (List[int]): 部门 ID 列表。
|
||||
- ids (list[int]): 部门 ID 列表。
|
||||
|
||||
返回:
|
||||
- None
|
||||
|
||||
@@ -16,10 +16,13 @@ class DictTypeCRUD(CRUDBase[DictTypeModel, DictTypeCreateSchema, DictTypeUpdateS
|
||||
|
||||
def __init__(self, auth: AuthSchema) -> None:
|
||||
"""
|
||||
初始化数据字典类型CRUD
|
||||
初始化数据字典类型数据层。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
- auth (AuthSchema): 认证信息模型(含 DB 会话等上下文)。
|
||||
|
||||
返回:
|
||||
- None
|
||||
"""
|
||||
self.auth = auth
|
||||
super().__init__(model=DictTypeModel, auth=auth)
|
||||
@@ -119,7 +122,7 @@ class DictTypeCRUD(CRUDBase[DictTypeModel, DictTypeCreateSchema, DictTypeUpdateS
|
||||
批量删除数据字典类型
|
||||
|
||||
参数:
|
||||
- ids (List[int]): 数据字典类型ID列表
|
||||
- ids (list[int]): 数据字典类型ID列表
|
||||
|
||||
返回:
|
||||
- int: 删除的记录数量
|
||||
@@ -133,10 +136,13 @@ class DictDataCRUD(CRUDBase[DictDataModel, DictDataCreateSchema, DictDataUpdateS
|
||||
|
||||
def __init__(self, auth: AuthSchema) -> None:
|
||||
"""
|
||||
初始化数据字典数据CRUD
|
||||
初始化数据字典项数据层。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
- auth (AuthSchema): 认证信息模型(含 DB 会话等上下文)。
|
||||
|
||||
返回:
|
||||
- None
|
||||
"""
|
||||
self.auth = auth
|
||||
super().__init__(model=DictDataModel, auth=auth)
|
||||
@@ -236,7 +242,7 @@ class DictDataCRUD(CRUDBase[DictDataModel, DictDataCreateSchema, DictDataUpdateS
|
||||
批量删除数据字典数据
|
||||
|
||||
参数:
|
||||
- ids (List[int]): 数据字典数据ID列表
|
||||
- ids (list[int]): 数据字典数据ID列表
|
||||
- exclude_system (bool): 是否排除系统默认数据,默认为True
|
||||
|
||||
返回:
|
||||
|
||||
@@ -26,12 +26,36 @@ class DictTypeCreateSchema(BaseModel):
|
||||
|
||||
@field_validator("dict_name")
|
||||
def validate_dict_name(cls, value: str):
|
||||
"""
|
||||
校验字典名称为非空字符串。
|
||||
|
||||
参数:
|
||||
- value (str): 字典名称。
|
||||
|
||||
返回:
|
||||
- str: 去首尾空格后的字典名称。
|
||||
|
||||
异常:
|
||||
- ValueError: 字典名称为空时抛出。
|
||||
"""
|
||||
if not value or value.strip() == "":
|
||||
raise ValueError("字典名称不能为空")
|
||||
return value.strip()
|
||||
|
||||
@field_validator("dict_type")
|
||||
def validate_dict_type(cls, value: str):
|
||||
"""
|
||||
校验字典类型:小写字母开头,仅包含小写字母/数字/下划线。
|
||||
|
||||
参数:
|
||||
- value (str): 字典类型。
|
||||
|
||||
返回:
|
||||
- str: 去首尾空格后的字典类型。
|
||||
|
||||
异常:
|
||||
- ValueError: 字典类型为空或不满足格式要求时抛出。
|
||||
"""
|
||||
if not value or value.strip() == "":
|
||||
raise ValueError("字典类型不能为空")
|
||||
regexp = r"^[a-z][a-z0-9_]*$"
|
||||
@@ -105,6 +129,15 @@ class DictDataCreateSchema(BaseModel):
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_after(self):
|
||||
"""
|
||||
校验并规范化字典数据字段(标签/键值/类型/类型ID)。
|
||||
|
||||
返回:
|
||||
- DictDataCreateSchema: 校验与去空格后的同一实例。
|
||||
|
||||
异常:
|
||||
- ValueError: 必填字段为空或类型ID非法时抛出。
|
||||
"""
|
||||
if not self.dict_label or not self.dict_label.strip():
|
||||
raise ValueError("字典标签不能为空")
|
||||
if not self.dict_value or not self.dict_value.strip():
|
||||
|
||||
@@ -76,7 +76,19 @@ class DictTypeService:
|
||||
search: DictTypeQueryParam | None = None,
|
||||
order_by: list[dict] | None = None,
|
||||
) -> dict:
|
||||
"""分页查询字典类型(数据库 OFFSET/LIMIT)。"""
|
||||
"""
|
||||
分页查询字典类型(数据库 OFFSET/LIMIT)。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
- page_no (int): 页码(从 1 开始)
|
||||
- page_size (int): 每页条数
|
||||
- search (DictTypeQueryParam | None): 查询条件
|
||||
- order_by (list[dict] | None): 排序字段列表
|
||||
|
||||
返回:
|
||||
- dict: 分页结果(结构由 `CRUD.page` 返回约定)
|
||||
"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await DictTypeCRUD(auth).page(
|
||||
offset=offset,
|
||||
@@ -336,7 +348,19 @@ class DictDataService:
|
||||
search: DictDataQueryParam | None = None,
|
||||
order_by: list[dict] | None = None,
|
||||
) -> dict:
|
||||
"""分页查询字典数据(数据库 OFFSET/LIMIT)。"""
|
||||
"""
|
||||
分页查询字典数据(数据库 OFFSET/LIMIT)。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
- page_no (int): 页码(从 1 开始)
|
||||
- page_size (int): 每页条数
|
||||
- search (DictDataQueryParam | None): 查询条件
|
||||
- order_by (list[dict] | None): 排序字段列表
|
||||
|
||||
返回:
|
||||
- dict: 分页结果(结构由 `CRUD.page` 返回约定)
|
||||
"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await DictDataCRUD(auth).page(
|
||||
offset=offset,
|
||||
|
||||
@@ -16,7 +16,13 @@ class OperationLogCRUD(
|
||||
|
||||
def __init__(self, auth: AuthSchema) -> None:
|
||||
"""
|
||||
初始化操作日志CRUD。
|
||||
初始化操作日志数据层。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型(含 DB 会话等上下文)。
|
||||
|
||||
返回:
|
||||
- None
|
||||
"""
|
||||
self.auth = auth
|
||||
super().__init__(model=OperationLogModel, auth=auth)
|
||||
@@ -58,9 +64,9 @@ class OperationLogCRUD(
|
||||
获取操作日志列表。
|
||||
|
||||
参数:
|
||||
- search (Dict | None): 搜索条件字典。
|
||||
- order_by (List[Dict[str, str]] | None): 排序字段列表。
|
||||
- preload (Optional[List[Union[str, Any]]]): 预加载关系,未提供时使用模型默认项
|
||||
- search (dict | None): 搜索条件字典。
|
||||
- order_by (list | None): 排序字段列表。
|
||||
- preload (list | None): 预加载关系,未提供时使用模型默认项
|
||||
|
||||
返回:
|
||||
- Sequence[OperationLogModel]: 操作日志列表。
|
||||
|
||||
@@ -6,12 +6,22 @@ from app.core.base_model import ModelMixin, UserMixin
|
||||
|
||||
|
||||
def get_log_text_column_type():
|
||||
"""
|
||||
根据数据库类型选择适合存储大文本的列类型。
|
||||
|
||||
MySQL 使用 LONGTEXT,PostgreSQL 使用 TEXT,其它数据库回退到 SQLAlchemy 的 Text。
|
||||
|
||||
返回:
|
||||
- type: SQLAlchemy 列类型(可用于 mapped_column)。
|
||||
"""
|
||||
db_type = settings.DATABASE_TYPE
|
||||
if db_type == "mysql":
|
||||
from sqlalchemy.dialects.mysql import LONGTEXT
|
||||
|
||||
return LONGTEXT
|
||||
elif db_type == "postgres":
|
||||
from sqlalchemy.dialects.postgresql import TEXT
|
||||
|
||||
return TEXT
|
||||
else:
|
||||
return Text
|
||||
|
||||
@@ -65,7 +65,19 @@ class OperationLogService:
|
||||
search: OperationLogQueryParam | None = None,
|
||||
order_by: list | None = None,
|
||||
) -> dict:
|
||||
"""分页查询操作日志(数据库 OFFSET/LIMIT)。"""
|
||||
"""
|
||||
分页查询操作日志(数据库 OFFSET/LIMIT)。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
- page_no (int): 页码(从 1 开始)
|
||||
- page_size (int): 每页条数
|
||||
- search (OperationLogQueryParam | None): 查询条件
|
||||
- order_by (list | None): 排序字段列表
|
||||
|
||||
返回:
|
||||
- dict: 分页结果(结构由 `CRUD.page` 返回约定)
|
||||
"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await OperationLogCRUD(auth).page(
|
||||
offset=offset,
|
||||
|
||||
@@ -11,7 +11,15 @@ class MenuCRUD(CRUDBase[MenuModel, MenuCreateSchema, MenuUpdateSchema]):
|
||||
"""菜单模块数据层"""
|
||||
|
||||
def __init__(self, auth: AuthSchema) -> None:
|
||||
"""初始化菜单CRUD"""
|
||||
"""
|
||||
初始化菜单数据层。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型(含 DB 会话等上下文)。
|
||||
|
||||
返回:
|
||||
- None
|
||||
"""
|
||||
self.auth = auth
|
||||
super().__init__(model=MenuModel, auth=auth)
|
||||
|
||||
|
||||
@@ -72,6 +72,15 @@ class MenuCreateSchema(BaseModel):
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_fields(self):
|
||||
"""
|
||||
统一校验菜单请求字段(委托到 `menu_request_validator`)。
|
||||
|
||||
返回:
|
||||
- MenuCreateSchema: 校验后的同一实例。
|
||||
|
||||
异常:
|
||||
- CustomException: 字段不满足菜单类型约束时抛出。
|
||||
"""
|
||||
return menu_request_validator(self)
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,31 @@ class MenuService:
|
||||
菜单模块服务层
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
async def _validate_parent_child_type(
|
||||
cls, auth: AuthSchema, parent_id: int | None, child_type: int
|
||||
) -> None:
|
||||
"""
|
||||
父子类型约束:目录下仅允许目录/菜单/外链;菜单下仅允许按钮;按钮与外链下不可挂子级。
|
||||
无父级时仅允许目录、菜单、外链(与前端一致)。
|
||||
"""
|
||||
if parent_id is None:
|
||||
if child_type not in (1, 2, 4):
|
||||
raise CustomException(msg="顶级菜单仅允许目录、菜单或外链类型")
|
||||
return
|
||||
parent = await MenuCRUD(auth).get_by_id_crud(id=parent_id)
|
||||
if not parent:
|
||||
raise CustomException(msg="父级菜单不存在")
|
||||
pt = parent.type
|
||||
if pt == 1:
|
||||
if child_type not in (1, 2, 4):
|
||||
raise CustomException(msg="目录下仅允许新增目录、菜单或外链")
|
||||
elif pt == 2:
|
||||
if child_type != 3:
|
||||
raise CustomException(msg="菜单下仅允许新增按钮")
|
||||
else:
|
||||
raise CustomException(msg="菜单或链接类型下不允许新增子菜单")
|
||||
|
||||
@classmethod
|
||||
async def get_menu_detail_service(cls, auth: AuthSchema, id: int) -> dict:
|
||||
"""
|
||||
@@ -93,6 +118,8 @@ class MenuService:
|
||||
if menu:
|
||||
raise CustomException(msg="创建失败,该菜单已存在")
|
||||
|
||||
await cls._validate_parent_child_type(auth, data.parent_id, data.type)
|
||||
|
||||
new_menu = await MenuCRUD(auth).create(data=data)
|
||||
new_menu_dict = MenuOutSchema.model_validate(new_menu).model_dump()
|
||||
return new_menu_dict
|
||||
@@ -113,6 +140,7 @@ class MenuService:
|
||||
menu = await MenuCRUD(auth).get_by_id_crud(id=id)
|
||||
if not menu:
|
||||
raise CustomException(msg="更新失败,该菜单不存在")
|
||||
await cls._validate_parent_child_type(auth, data.parent_id, data.type)
|
||||
search: dict[str, Any] = {"title": data.title}
|
||||
if data.parent_id is not None:
|
||||
search["parent_id"] = data.parent_id
|
||||
|
||||
@@ -15,7 +15,10 @@ class NoticeCRUD(CRUDBase[NoticeModel, NoticeCreateSchema, NoticeUpdateSchema]):
|
||||
初始化公告数据层。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型。
|
||||
- auth (AuthSchema): 认证信息模型(含 DB 会话等上下文)。
|
||||
|
||||
返回:
|
||||
- None
|
||||
"""
|
||||
self.auth = auth
|
||||
super().__init__(model=NoticeModel, auth=auth)
|
||||
|
||||
@@ -84,7 +84,19 @@ class NoticeService:
|
||||
search: NoticeQueryParam | None = None,
|
||||
order_by: list[dict] | None = None,
|
||||
) -> dict:
|
||||
"""分页查询公告(数据库 OFFSET/LIMIT)。"""
|
||||
"""
|
||||
分页查询公告(数据库 OFFSET/LIMIT)。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
- page_no (int): 页码(从 1 开始)
|
||||
- page_size (int): 每页条数
|
||||
- search (NoticeQueryParam | None): 查询条件
|
||||
- order_by (list[dict] | None): 排序字段列表
|
||||
|
||||
返回:
|
||||
- dict: 分页结果(结构由 `CRUD.page` 返回约定)
|
||||
"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await NoticeCRUD(auth).page(
|
||||
offset=offset,
|
||||
@@ -96,7 +108,15 @@ class NoticeService:
|
||||
|
||||
@classmethod
|
||||
async def get_notice_available_page_service(cls, auth: AuthSchema) -> dict:
|
||||
"""已启用公告分页(与历史行为一致:默认第 1 页、每页 10 条)。"""
|
||||
"""
|
||||
已启用公告分页(与历史行为一致:固定第 1 页、每页 10 条)。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
|
||||
返回:
|
||||
- dict: 分页结果(结构由 `CRUD.page` 返回约定)
|
||||
"""
|
||||
return await NoticeCRUD(auth).page(
|
||||
offset=0,
|
||||
limit=10,
|
||||
@@ -164,6 +184,9 @@ class NoticeService:
|
||||
|
||||
异常:
|
||||
- CustomException: 删除失败,删除对象不能为空或该公告通知不存在。
|
||||
|
||||
返回:
|
||||
- None
|
||||
"""
|
||||
if len(ids) < 1:
|
||||
raise CustomException(msg="删除失败,删除对象不能为空")
|
||||
@@ -184,6 +207,9 @@ class NoticeService:
|
||||
|
||||
异常:
|
||||
- CustomException: 批量设置失败,该公告通知不存在。
|
||||
|
||||
返回:
|
||||
- None
|
||||
"""
|
||||
await NoticeCRUD(auth).set_available_crud(ids=data.ids, status=data.status)
|
||||
|
||||
|
||||
@@ -12,10 +12,13 @@ class ParamsCRUD(CRUDBase[ParamsModel, ParamsCreateSchema, ParamsUpdateSchema]):
|
||||
|
||||
def __init__(self, auth: AuthSchema) -> None:
|
||||
"""
|
||||
初始化配置CRUD
|
||||
初始化系统参数配置数据层。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
- auth (AuthSchema): 认证信息模型(含 DB 会话等上下文)。
|
||||
|
||||
返回:
|
||||
- None
|
||||
"""
|
||||
self.auth = auth
|
||||
super().__init__(model=ParamsModel, auth=auth)
|
||||
|
||||
@@ -112,7 +112,19 @@ class ParamsService:
|
||||
search: ParamsQueryParam | None = None,
|
||||
order_by: list[dict[str, str]] | None = None,
|
||||
) -> dict:
|
||||
"""分页查询参数(数据库 OFFSET/LIMIT)。"""
|
||||
"""
|
||||
分页查询系统参数(数据库 OFFSET/LIMIT)。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
- page_no (int): 页码(从 1 开始)
|
||||
- page_size (int): 每页条数
|
||||
- search (ParamsQueryParam | None): 查询条件
|
||||
- order_by (list[dict[str, str]] | None): 排序字段列表
|
||||
|
||||
返回:
|
||||
- dict: 分页结果(结构由 `CRUD.page` 返回约定)
|
||||
"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await ParamsCRUD(auth).page(
|
||||
offset=offset,
|
||||
|
||||
@@ -13,10 +13,13 @@ class PositionCRUD(CRUDBase[PositionModel, PositionCreateSchema, PositionUpdateS
|
||||
|
||||
def __init__(self, auth: AuthSchema) -> None:
|
||||
"""
|
||||
初始化岗位CRUD
|
||||
初始化岗位数据层。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
- auth (AuthSchema): 认证信息模型(含 DB 会话等上下文)。
|
||||
|
||||
返回:
|
||||
- None
|
||||
"""
|
||||
self.auth = auth
|
||||
super().__init__(model=PositionModel, auth=auth)
|
||||
|
||||
@@ -64,7 +64,19 @@ class PositionService:
|
||||
search: PositionQueryParam | None = None,
|
||||
order_by: list[dict[str, str]] | None = None,
|
||||
) -> dict:
|
||||
"""分页查询岗位(数据库 OFFSET/LIMIT)。"""
|
||||
"""
|
||||
分页查询岗位(数据库 OFFSET/LIMIT)。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
- page_no (int): 页码(从 1 开始)
|
||||
- page_size (int): 每页条数
|
||||
- search (PositionQueryParam | None): 查询条件
|
||||
- order_by (list[dict[str, str]] | None): 排序字段列表
|
||||
|
||||
返回:
|
||||
- dict: 分页结果(结构由 `CRUD.page` 返回约定)
|
||||
"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await PositionCRUD(auth).page(
|
||||
offset=offset,
|
||||
@@ -84,7 +96,7 @@ class PositionService:
|
||||
- data (PositionCreateSchema): 岗位创建模型
|
||||
|
||||
返回:
|
||||
- Dict: 创建的岗位对象
|
||||
- dict: 创建的岗位详情字典
|
||||
"""
|
||||
position = await PositionCRUD(auth).get(name=data.name)
|
||||
if position:
|
||||
|
||||
@@ -14,10 +14,13 @@ class RoleCRUD(CRUDBase[RoleModel, RoleCreateSchema, RoleUpdateSchema]):
|
||||
|
||||
def __init__(self, auth: AuthSchema) -> None:
|
||||
"""
|
||||
初始化角色模块数据层
|
||||
初始化角色数据层。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
- auth (AuthSchema): 认证信息模型(含 DB 会话等上下文)。
|
||||
|
||||
返回:
|
||||
- None
|
||||
"""
|
||||
self.auth = auth
|
||||
super().__init__(model=RoleModel, auth=auth)
|
||||
@@ -59,8 +62,8 @@ class RoleCRUD(CRUDBase[RoleModel, RoleCreateSchema, RoleUpdateSchema]):
|
||||
设置角色的菜单权限
|
||||
|
||||
参数:
|
||||
- role_ids (List[int]): 角色ID列表
|
||||
- menu_ids (List[int]): 菜单ID列表
|
||||
- role_ids (list[int]): 角色ID列表
|
||||
- menu_ids (list[int]): 菜单ID列表
|
||||
|
||||
返回:
|
||||
- None
|
||||
|
||||
@@ -34,6 +34,18 @@ class RoleCreateSchema(BaseModel):
|
||||
@field_validator("code")
|
||||
@classmethod
|
||||
def validate_code(cls, value: str | None):
|
||||
"""
|
||||
校验角色编码(委托到 `code_validator`)。
|
||||
|
||||
参数:
|
||||
- value (str | None): 角色编码。
|
||||
|
||||
返回:
|
||||
- str | None: 校验后的角色编码。
|
||||
|
||||
异常:
|
||||
- CustomException: 不满足编码规则时抛出。
|
||||
"""
|
||||
return code_validator(value)
|
||||
|
||||
|
||||
@@ -50,7 +62,18 @@ class RolePermissionSettingSchema(BaseModel):
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_fields(self):
|
||||
"""验证权限配置字段"""
|
||||
"""
|
||||
校验角色权限配置字段(数据范围与关联 ID 等)。
|
||||
|
||||
参数:
|
||||
- self: 当前模型实例(校验后状态)。
|
||||
|
||||
返回:
|
||||
- RolePermissionSettingSchema: 通过 `role_permission_request_validator` 校验后的同一实例。
|
||||
|
||||
异常:
|
||||
- CustomException: 不满足权限配置约束时抛出。
|
||||
"""
|
||||
return role_permission_request_validator(self)
|
||||
|
||||
|
||||
|
||||
@@ -63,7 +63,19 @@ class RoleService:
|
||||
search: RoleQueryParam | None = None,
|
||||
order_by: list[dict[str, str]] | None = None,
|
||||
) -> dict:
|
||||
"""分页查询角色(数据库 OFFSET/LIMIT)。"""
|
||||
"""
|
||||
分页查询角色(数据库 OFFSET/LIMIT)。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
- page_no (int): 页码(从 1 开始)
|
||||
- page_size (int): 每页条数
|
||||
- search (RoleQueryParam | None): 查询条件
|
||||
- order_by (list[dict[str, str]] | None): 排序字段列表
|
||||
|
||||
返回:
|
||||
- dict: 分页结果(结构由 `CRUD.page` 返回约定)
|
||||
"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await RoleCRUD(auth).page(
|
||||
offset=offset,
|
||||
|
||||
@@ -20,10 +20,13 @@ class UserCRUD(CRUDBase[UserModel, UserCreateSchema, UserUpdateSchema]):
|
||||
|
||||
def __init__(self, auth: AuthSchema) -> None:
|
||||
"""
|
||||
初始化用户CRUD
|
||||
初始化用户数据层。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
- auth (AuthSchema): 认证信息模型(含 DB 会话等上下文)。
|
||||
|
||||
返回:
|
||||
- None
|
||||
"""
|
||||
self.auth = auth
|
||||
super().__init__(model=UserModel, auth=auth)
|
||||
@@ -123,10 +126,10 @@ class UserCRUD(CRUDBase[UserModel, UserCreateSchema, UserUpdateSchema]):
|
||||
|
||||
参数:
|
||||
- ids (list[int]): 用户ID列表
|
||||
- status (bool): 可用状态
|
||||
- status (str): 可用状态(与表字段一致,如 "0"/"1")
|
||||
|
||||
返回:
|
||||
- None:
|
||||
- None
|
||||
"""
|
||||
await self.set(ids=ids, status=status)
|
||||
|
||||
@@ -139,7 +142,7 @@ class UserCRUD(CRUDBase[UserModel, UserCreateSchema, UserUpdateSchema]):
|
||||
- role_ids (list[int]): 角色ID列表
|
||||
|
||||
返回:
|
||||
- None:
|
||||
- None
|
||||
"""
|
||||
user_objs = await self.list(search={"id": ("in", user_ids)})
|
||||
if role_ids:
|
||||
@@ -162,7 +165,7 @@ class UserCRUD(CRUDBase[UserModel, UserCreateSchema, UserUpdateSchema]):
|
||||
- position_ids (list[int]): 岗位ID列表
|
||||
|
||||
返回:
|
||||
- None:
|
||||
- None
|
||||
"""
|
||||
user_objs = await self.list(search={"id": ("in", user_ids)})
|
||||
if position_ids:
|
||||
|
||||
@@ -29,11 +29,35 @@ class CurrentUserUpdateSchema(BaseModel):
|
||||
@field_validator("mobile")
|
||||
@classmethod
|
||||
def validate_mobile(cls, value: str | None):
|
||||
"""
|
||||
校验手机号格式(委托到 `mobile_validator`)。
|
||||
|
||||
参数:
|
||||
- value (str | None): 手机号。
|
||||
|
||||
返回:
|
||||
- str | None: 校验后的手机号。
|
||||
|
||||
异常:
|
||||
- CustomException: 手机号格式非法时抛出。
|
||||
"""
|
||||
return mobile_validator(value)
|
||||
|
||||
@field_validator("email")
|
||||
@classmethod
|
||||
def validate_email(cls, value: str | None):
|
||||
"""
|
||||
校验邮箱格式(为空则跳过;否则委托到 `email_validator`)。
|
||||
|
||||
参数:
|
||||
- value (str | None): 邮箱。
|
||||
|
||||
返回:
|
||||
- str | None: 校验后的邮箱。
|
||||
|
||||
异常:
|
||||
- CustomException: 邮箱格式非法时抛出。
|
||||
"""
|
||||
if not value:
|
||||
return value
|
||||
return email_validator(value)
|
||||
@@ -41,6 +65,18 @@ class CurrentUserUpdateSchema(BaseModel):
|
||||
@field_validator("avatar")
|
||||
@classmethod
|
||||
def validate_avatar(cls, value: str | None):
|
||||
"""
|
||||
校验头像地址为合法的 HTTP/HTTPS URL。
|
||||
|
||||
参数:
|
||||
- value (str | None): 头像 URL。
|
||||
|
||||
返回:
|
||||
- str | None: 校验后的头像 URL。
|
||||
|
||||
异常:
|
||||
- ValueError: 头像 URL 非法时抛出。
|
||||
"""
|
||||
if not value:
|
||||
return value
|
||||
parsed = urlparse(value)
|
||||
@@ -50,6 +86,15 @@ class CurrentUserUpdateSchema(BaseModel):
|
||||
|
||||
@model_validator(mode="after")
|
||||
def check_model(self):
|
||||
"""
|
||||
校验基础用户信息的长度约束。
|
||||
|
||||
返回:
|
||||
- CurrentUserUpdateSchema: 校验后的同一实例。
|
||||
|
||||
异常:
|
||||
- ValueError: 字段长度超限时抛出。
|
||||
"""
|
||||
if self.name and len(self.name) > 32:
|
||||
raise ValueError("名称长度不能超过32个字符")
|
||||
return self
|
||||
@@ -69,11 +114,35 @@ class UserRegisterSchema(BaseModel):
|
||||
@field_validator("mobile")
|
||||
@classmethod
|
||||
def validate_mobile(cls, value: str | None):
|
||||
"""
|
||||
校验手机号格式(委托到 `mobile_validator`)。
|
||||
|
||||
参数:
|
||||
- value (str | None): 手机号。
|
||||
|
||||
返回:
|
||||
- str | None: 校验后的手机号。
|
||||
|
||||
异常:
|
||||
- CustomException: 手机号格式非法时抛出。
|
||||
"""
|
||||
return mobile_validator(value)
|
||||
|
||||
@field_validator("username")
|
||||
@classmethod
|
||||
def validate_username(cls, value: str):
|
||||
"""
|
||||
校验并规范化账号:字母开头,长度 3-32,仅含字母/数字/_ . -。
|
||||
|
||||
参数:
|
||||
- value (str): 账号。
|
||||
|
||||
返回:
|
||||
- str: 规范化后的账号。
|
||||
|
||||
异常:
|
||||
- ValueError: 账号为空或不满足格式约束时抛出。
|
||||
"""
|
||||
v = value.strip()
|
||||
if not v:
|
||||
raise ValueError("账号不能为空")
|
||||
@@ -86,6 +155,15 @@ class UserRegisterSchema(BaseModel):
|
||||
|
||||
@model_validator(mode="after")
|
||||
def check_model(self):
|
||||
"""
|
||||
校验注册信息的长度约束。
|
||||
|
||||
返回:
|
||||
- UserRegisterSchema: 校验后的同一实例。
|
||||
|
||||
异常:
|
||||
- ValueError: 任一字段长度超限时抛出。
|
||||
"""
|
||||
if self.name and len(self.name) > 32:
|
||||
raise ValueError("名称长度不能超过32个字符")
|
||||
if self.username and len(self.username) > 32:
|
||||
@@ -107,6 +185,18 @@ class UserForgetPasswordSchema(BaseModel):
|
||||
@field_validator("mobile")
|
||||
@classmethod
|
||||
def validate_mobile(cls, value: str | None):
|
||||
"""
|
||||
校验手机号格式(委托到 `mobile_validator`)。
|
||||
|
||||
参数:
|
||||
- value (str | None): 手机号。
|
||||
|
||||
返回:
|
||||
- str | None: 校验后的手机号。
|
||||
|
||||
异常:
|
||||
- CustomException: 手机号格式非法时抛出。
|
||||
"""
|
||||
return mobile_validator(value)
|
||||
|
||||
|
||||
|
||||
@@ -95,7 +95,19 @@ class UserService:
|
||||
search: UserQueryParam | None = None,
|
||||
order_by: list[dict[str, str]] | None = None,
|
||||
) -> dict:
|
||||
"""分页查询用户(数据库 OFFSET/LIMIT)。"""
|
||||
"""
|
||||
分页查询用户(数据库 OFFSET/LIMIT)。
|
||||
|
||||
参数:
|
||||
- auth (AuthSchema): 认证信息模型
|
||||
- page_no (int): 页码(从 1 开始)
|
||||
- page_size (int): 每页条数
|
||||
- search (UserQueryParam | None): 查询条件
|
||||
- order_by (list[dict[str, str]] | None): 排序字段列表
|
||||
|
||||
返回:
|
||||
- dict: 分页结果(结构由 `CRUD.page` 返回约定)
|
||||
"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await UserCRUD(auth).page(
|
||||
offset=offset,
|
||||
@@ -677,7 +689,7 @@ class UserService:
|
||||
导出用户列表为Excel文件
|
||||
|
||||
参数:
|
||||
- user_list (List[Dict[str, Any]]): 用户列表
|
||||
- user_list (list[dict[str, Any]]): 用户列表
|
||||
|
||||
返回:
|
||||
- bytes: Excel文件字节流
|
||||
|
||||
Reference in New Issue
Block a user