2026-10-09 06:46:36 -04:00
|
|
|
|
"""ORM 基类、命名约定与公共列。
|
|
|
|
|
|
|
|
|
|
|
|
命名约定按 PROJECT_STANDARDS 红线设置,使 Alembic autogenerate 产出的
|
|
|
|
|
|
约束名自动符合规范(唯一键 `uk_表_字段`、索引 `idx_表_字段`),
|
|
|
|
|
|
无需在每张表上手工指定 —— 手工指定迟早会漏。
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
2026-10-12 21:49:05 -04:00
|
|
|
|
from sqlalchemy import DateTime, MetaData, String, text
|
2026-10-09 06:46:36 -04:00
|
|
|
|
from sqlalchemy.dialects.mysql import BIGINT, TINYINT
|
|
|
|
|
|
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
|
|
|
|
|
|
|
|
|
|
|
# 约束命名模板。`column_0_name` 取约束涉及的第一列,
|
|
|
|
|
|
# 对单列唯一键/索引即为字段名,符合规范的 uk_表_字段 / idx_表_字段
|
|
|
|
|
|
NAMING_CONVENTION = {
|
|
|
|
|
|
"ix": "idx_%(table_name)s_%(column_0_name)s",
|
|
|
|
|
|
"uq": "uk_%(table_name)s_%(column_0_name)s",
|
|
|
|
|
|
"ck": "ck_%(table_name)s_%(constraint_name)s",
|
|
|
|
|
|
"fk": "fk_%(table_name)s_%(column_0_name)s",
|
|
|
|
|
|
"pk": "pk_%(table_name)s",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# 主键与外键统一使用无符号 BIGINT(规范模板为 BIGINT UNSIGNED)。
|
|
|
|
|
|
# 两边类型必须完全一致,否则 MySQL 拒绝建立外键约束。
|
|
|
|
|
|
BIGINT_UNSIGNED = BIGINT(unsigned=True)
|
|
|
|
|
|
|
|
|
|
|
|
# 状态类字段统一用 TINYINT(0/1 或少量枚举值)
|
|
|
|
|
|
TINYINT_TYPE = TINYINT
|
|
|
|
|
|
|
2026-10-12 21:49:05 -04:00
|
|
|
|
__all__ = [
|
|
|
|
|
|
"BIGINT_UNSIGNED",
|
|
|
|
|
|
"TINYINT_TYPE",
|
|
|
|
|
|
"Base",
|
|
|
|
|
|
"TPlusSyncMixin",
|
|
|
|
|
|
"TimestampMixin",
|
|
|
|
|
|
"mysql_table_args",
|
|
|
|
|
|
]
|
2026-10-09 06:46:36 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Base(DeclarativeBase):
|
|
|
|
|
|
"""全部 ORM 模型的基类。"""
|
|
|
|
|
|
|
|
|
|
|
|
metadata = MetaData(naming_convention=NAMING_CONVENTION)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TimestampMixin:
|
|
|
|
|
|
"""创建时间 / 更新时间公共列。
|
|
|
|
|
|
|
|
|
|
|
|
取默认值交给数据库而非应用层:即使有人直接用 SQL 改数据,时间戳依然准确;
|
|
|
|
|
|
应用层赋值则会被绕过。
|
|
|
|
|
|
|
|
|
|
|
|
`update_time` 必须用 `text("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")`
|
|
|
|
|
|
而非 `server_onupdate=func.current_timestamp()` —— 后者只是告诉 ORM
|
|
|
|
|
|
「这个值由服务端维护」,**不会生成 ON UPDATE 子句**,结果是更新时间永远不刷新。
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
create_time: Mapped[datetime] = mapped_column(
|
|
|
|
|
|
DateTime,
|
|
|
|
|
|
nullable=False,
|
|
|
|
|
|
server_default=text("CURRENT_TIMESTAMP"),
|
|
|
|
|
|
comment="创建时间",
|
|
|
|
|
|
)
|
|
|
|
|
|
update_time: Mapped[datetime] = mapped_column(
|
|
|
|
|
|
DateTime,
|
|
|
|
|
|
nullable=False,
|
|
|
|
|
|
server_default=text("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"),
|
|
|
|
|
|
comment="更新时间",
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-10-12 21:49:05 -04:00
|
|
|
|
class TPlusSyncMixin:
|
|
|
|
|
|
"""T+(用友)数据同步预留列,六张业务主表共用。
|
|
|
|
|
|
|
|
|
|
|
|
对照表 #26:T+ 对接的字段映射与幂等键语义未定(IT 牵头),故四列全部
|
|
|
|
|
|
可空、不设唯一键 —— 键语义未定就锁死唯一约束,对接时大概率返工;
|
|
|
|
|
|
source_no 先建普通索引承担查询与去重,IT 定键后以小迁移升级唯一约束。
|
|
|
|
|
|
|
|
|
|
|
|
同步守则(M4 同步模块必须遵守):同步只写 T+ 侧字段与本组列,
|
|
|
|
|
|
**不覆盖人工维护字段**(岗位/工资标准/归属/客户分类/业务状态等,
|
|
|
|
|
|
各表注释已标注)。同步频率:一周一次定时 + 手动触发(对照表 #10)。
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
source_no: Mapped[str | None] = mapped_column(
|
|
|
|
|
|
String(64),
|
|
|
|
|
|
index=True,
|
|
|
|
|
|
comment="T+ 原始单据号(同步幂等去重锚点;唯一键待 IT 定键后升级)",
|
|
|
|
|
|
)
|
|
|
|
|
|
t_plus_id: Mapped[str | None] = mapped_column(String(64), comment="T+ 系统内部标识")
|
|
|
|
|
|
sync_batch_no: Mapped[str | None] = mapped_column(
|
|
|
|
|
|
String(32), comment="同步批次号(同步模块写入)"
|
|
|
|
|
|
)
|
|
|
|
|
|
synced_at: Mapped[datetime | None] = mapped_column(DateTime, comment="最近同步时间")
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-10-09 06:46:36 -04:00
|
|
|
|
def mysql_table_args(comment: str, *extra: object) -> tuple[object, ...]:
|
|
|
|
|
|
"""构造 MySQL 表的公共参数,返回可直接赋给 `__table_args__` 的元组。
|
|
|
|
|
|
|
|
|
|
|
|
显式指定引擎、字符集与排序规则:compose 已把服务端排序规则覆盖为
|
|
|
|
|
|
`utf8mb4_general_ci`,若某处按 MySQL 8.0 默认的 `utf8mb4_0900_ai_ci` 建表,
|
|
|
|
|
|
跨表 JOIN 会报 `Illegal mix of collations`。
|
|
|
|
|
|
|
|
|
|
|
|
:param comment: 表注释(规范红线要求中文 COMMENT)
|
|
|
|
|
|
:param extra: 额外的约束对象(UniqueConstraint / Index 等)
|
|
|
|
|
|
"""
|
|
|
|
|
|
return (
|
|
|
|
|
|
*extra,
|
|
|
|
|
|
{
|
|
|
|
|
|
"mysql_engine": "InnoDB",
|
|
|
|
|
|
"mysql_charset": "utf8mb4",
|
|
|
|
|
|
"mysql_collate": "utf8mb4_general_ci",
|
|
|
|
|
|
"comment": comment,
|
|
|
|
|
|
},
|
|
|
|
|
|
)
|