216 lines
6.6 KiB
Markdown
216 lines
6.6 KiB
Markdown
# 数据模型(Model)
|
||
|
||
数据模型是模块开发的第一步,用于定义数据库表结构。项目使用 `SQLAlchemy ORM`,模型类通过继承基类自动获得通用字段和方法。
|
||
|
||
## 文件位置
|
||
|
||
```
|
||
src/modules/system/position/models.py
|
||
```
|
||
|
||
## 完整代码
|
||
|
||
以下为 `src/modules/system/position/models.py` 的核心代码(省略版权头):
|
||
|
||
```python
|
||
"""
|
||
岗位模型模块
|
||
=============================================================
|
||
|
||
提供岗位管理的数据模型定义,用于定义员工岗位信息。
|
||
|
||
企业级特性:
|
||
1. 使用枚举类管理状态常量,确保类型安全
|
||
2. 状态文本自动转换,便于前端展示
|
||
3. 便捷的查询方法,提高开发效率
|
||
4. 继承 BaseModel 和 BaseDB,复用通用功能
|
||
5. __init__ 由 BaseModel 统一管理,无需重复定义
|
||
"""
|
||
|
||
from enum import IntEnum
|
||
from typing import Optional, List
|
||
|
||
from src.common.base_db import BaseDB
|
||
from src.common.base_model import BaseModel
|
||
from config import DB_PREFIX
|
||
from sqlalchemy import text
|
||
from src.core.database import db
|
||
from src.common.utils.request import like_contains
|
||
|
||
|
||
# ============================================================
|
||
# 岗位状态枚举
|
||
# ============================================================
|
||
|
||
class PositionStatus(IntEnum):
|
||
"""
|
||
岗位状态枚举
|
||
|
||
使用 IntEnum 确保类型安全,避免魔法数字。
|
||
可直接用于数据库查询和比较。
|
||
"""
|
||
DISABLED = 0 # 停用
|
||
ENABLED = 1 # 启用
|
||
|
||
|
||
# ============================================================
|
||
# 岗位模型
|
||
# ============================================================
|
||
|
||
class Position(BaseModel, BaseDB):
|
||
"""
|
||
岗位模型
|
||
|
||
用于存储员工岗位信息,如:技术总监、产品经理等。
|
||
继承自 BaseModel(通用字段)和 BaseDB(数据库操作方法)。
|
||
"""
|
||
|
||
# 表名:使用配置前缀 + 模型名
|
||
__tablename__ = DB_PREFIX + "position"
|
||
__table_comment__ = "岗位表"
|
||
|
||
# ============================================================
|
||
# 字段定义
|
||
# ============================================================
|
||
|
||
# 岗位名称:必填字段,最长255字符
|
||
name = db.Column(
|
||
db.String(255),
|
||
nullable=False,
|
||
index=True,
|
||
comment="岗位名称"
|
||
)
|
||
|
||
# 岗位状态:使用枚举确保类型安全
|
||
# 默认值为停用,创建后需手动启用
|
||
status = db.Column(
|
||
db.Integer,
|
||
index=True,
|
||
default=PositionStatus.DISABLED,
|
||
server_default=text('0'),
|
||
comment="岗位状态:0-停用 1-启用"
|
||
)
|
||
|
||
# 岗位排序:数值越小越靠前
|
||
sort = db.Column(
|
||
db.Integer,
|
||
default=0,
|
||
server_default=text('0'),
|
||
comment="岗位排序"
|
||
)
|
||
|
||
# ============================================================
|
||
# 注意:__init__ 方法在 BaseModel 中已实现,无需重复定义
|
||
# BaseModel 已处理驼峰转换、字段过滤等逻辑
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# 便捷属性
|
||
# ============================================================
|
||
|
||
@property
|
||
def status_text(self) -> str:
|
||
"""获取岗位状态文本:将数字状态转换为可读的中文文本"""
|
||
status_map = {
|
||
PositionStatus.DISABLED: '停用',
|
||
PositionStatus.ENABLED: '启用'
|
||
}
|
||
return status_map.get(self.status, '未知')
|
||
|
||
@property
|
||
def is_enabled(self) -> bool:
|
||
"""判断岗位是否启用"""
|
||
return self.status == PositionStatus.ENABLED
|
||
|
||
@property
|
||
def is_disabled(self) -> bool:
|
||
"""判断岗位是否停用"""
|
||
return self.status == PositionStatus.DISABLED
|
||
|
||
# ============================================================
|
||
# 自定义查询方法
|
||
# ============================================================
|
||
|
||
@classmethod
|
||
def get_enabled(cls) -> List['Position']:
|
||
"""获取所有启用的岗位,按排序值升序排列"""
|
||
return cls.query.filter(
|
||
cls.is_delete == 0,
|
||
cls.status == PositionStatus.ENABLED
|
||
).order_by(cls.sort.asc()).all()
|
||
|
||
@classmethod
|
||
def get_by_name(cls, name: Optional[str]) -> Optional['Position']:
|
||
"""根据岗位名称精确查询"""
|
||
if not name:
|
||
return None
|
||
return cls.query.filter(
|
||
cls.name == name,
|
||
cls.is_delete == 0
|
||
).first()
|
||
|
||
def __repr__(self) -> str:
|
||
return f'岗位:{self.name}'
|
||
```
|
||
|
||
## 代码解析
|
||
|
||
### 基类继承
|
||
|
||
```python
|
||
class Position(BaseModel, BaseDB):
|
||
```
|
||
|
||
| 基类 | 来源 | 提供能力 |
|
||
|:----|:----|:----|
|
||
| `BaseModel` | `src/common/base_model.py` | 通用字段:id、create_user、create_time、update_user、update_time、is_delete |
|
||
| `BaseDB` | `src/common/base_db.py` | `save()` 持久化方法(仅 flush,不 commit)、`to_dict()` 序列化方法 |
|
||
|
||
### 状态枚举
|
||
|
||
项目推荐使用 `IntEnum` 管理状态常量,避免魔法数字:
|
||
|
||
```python
|
||
class PositionStatus(IntEnum):
|
||
DISABLED = 0 # 停用
|
||
ENABLED = 1 # 启用
|
||
```
|
||
|
||
| 值 | 含义 |
|
||
|:----|:----|
|
||
| 0 | 停用 / 禁用 |
|
||
| 1 | 启用 / 在用 |
|
||
|
||
软删除字段 `is_delete` 由基类提供:`0` = 正常,`1` = 已删除。
|
||
|
||
### 字段定义风格
|
||
|
||
项目使用 `db.Column`(从 `src.core.database` 导入的 `db` 实例),而非直接导入 `Column`:
|
||
|
||
```python
|
||
from src.core.database import db
|
||
|
||
name = db.Column(db.String(255), nullable=False, index=True, comment="岗位名称")
|
||
```
|
||
|
||
### 表名配置
|
||
|
||
```python
|
||
__tablename__ = DB_PREFIX + "position"
|
||
```
|
||
|
||
`DB_PREFIX` 从 `.env` 读取(默认 `flask_`),最终表名为 `flask_position`。
|
||
|
||
## 开发要点
|
||
|
||
1. **业务字段仅定义差异部分**:通用字段(id、时间、软删除等)由基类自动提供
|
||
2. **表名必须加 `DB_PREFIX` 前缀**:保持命名一致性
|
||
3. **使用 `db.Column` 而非直接导入 `Column`**:保持与项目一致的导入风格
|
||
4. **状态字段使用 IntEnum**:避免魔法数字,提高代码可读性
|
||
5. **同时设置 `default` 和 `server_default`**:确保 ORM 和直 SQL 两种场景都能正确赋默认值
|
||
6. **`__init__` 由 BaseModel 统一管理**:无需在子类中重复定义
|
||
|
||
## 总结
|
||
|
||
数据模型继承 `BaseModel`(公共字段)和 `BaseDB`(save 方法),表名必须加 `DB_PREFIX` 前缀。状态字段使用 `IntEnum` 枚举类管理,字段定义使用 `db.Column` 风格。`__init__` 由 BaseModel 统一处理驼峰转换和字段过滤,子类无需重复定义。
|