BaseModel 设计
概述
所有业务模型都继承 BaseModel,提供统一的主键生成、软删除、审计字段。
源码
python
from nanoid import generate
from sqlalchemy import Column, String, DateTime, Boolean, Integer
from sqlalchemy.sql import func
class BaseModel(Base):
"""公共基础模型"""
__abstract__ = True
id = Column(String(21), primary_key=True, default=generate_nanoid)
sort = Column(Integer, default=0, comment="排序")
is_deleted = Column(Boolean, default=False, index=True, comment="是否删除")
sys_create_datetime = Column(DateTime, server_default=func.now())
sys_update_datetime = Column(DateTime, server_default=func.now(), onupdate=func.now())
sys_creator_id = Column(String(21), nullable=True, comment="创建人ID")
sys_modifier_id = Column(String(21), nullable=True, comment="修改人ID")
sys_dept_id = Column(String(21), nullable=True, comment="部门ID")字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
id | String(21) | NanoID 主键,21 位随机字符串 |
sort | Integer | 排序字段,默认 0,降序排列 |
is_deleted | Boolean | 软删除标记,有索引 |
sys_create_datetime | DateTime | 创建时间,数据库层自动填充 |
sys_update_datetime | DateTime | 更新时间,数据库层自动更新 |
sys_creator_id | String(21) | 创建人 ID(逻辑外键 → core_user) |
sys_modifier_id | String(21) | 修改人 ID(逻辑外键 → core_user) |
sys_dept_id | String(21) | 所属部门 ID(逻辑外键 → core_dept) |
设计要点
NanoID 主键
使用 NanoID 替代自增 ID 或标准 UUID:
- 长度:21 位,比 UUID 短(36 位)
- 安全性:不暴露数据量和顺序
- 分布式友好:无需中心化 ID 生成器
- URL 安全:仅使用
A-Za-z0-9_-字符
python
from nanoid import generate
def generate_nanoid() -> str:
return generate(size=21)软删除
通过 is_deleted 字段实现逻辑删除:
is_deleted=False:正常数据is_deleted=True:已删除数据
BaseService 的所有查询方法默认过滤已删除数据。如需物理删除,设置 hard=True。
审计字段自动填充
BaseService 在创建和更新时自动填充审计字段:
- 创建时:自动设置
sys_creator_id、sys_dept_id(从请求上下文获取) - 更新时:自动设置
sys_modifier_id(从请求上下文获取) - 时间字段由数据库层自动管理
逻辑外键
sys_creator_id、sys_modifier_id、sys_dept_id 都使用逻辑外键,不创建数据库外键约束。
使用示例
python
from sqlalchemy import Column, String, Text, Boolean, Integer
from app.base_model import BaseModel
class Customer(BaseModel):
"""客户模型"""
__tablename__ = "biz_customer"
name = Column(String(100), nullable=False, comment="客户名称")
phone = Column(String(20), nullable=True, comment="电话")
email = Column(String(100), nullable=True, comment="邮箱")
address = Column(Text, nullable=True, comment="地址")
level = Column(Integer, default=0, comment="客户等级")
is_active = Column(Boolean, default=True, comment="是否启用")命名规范
- 表名:小写 + 下划线,模块前缀(如
core_user、biz_customer) - 字段:小写 + 下划线
- 字段注释:所有字段必须添加
comment - 字符串字段:指定长度(如
String(100))