Files
shanxia2.0/docs/dev-field-consistency.md
T
2026-05-23 14:49:50 +08:00

3.5 KiB
Raw Blame History

字段一致性开发指南

问题背景

在前后端全链路开发中,一个字段需要同时出现在 5 个位置 才能完整打通:

前端 formData → API Schema (Pydantic) → API Handler 传参 → CRUD 函数签名 → ORM 赋值

任何一层遗漏都会导致字段静默丢失(Pydantic 默认忽略未定义字段,不报错),产生难以发现的 bug。

历史问题

时间 问题 根因
2026-05 耗材/试剂新增时 warning_qty 未保存 Schema 缺字段 → Handler 没传 → CRUD 没接
2026-05 耗材/试剂新增时 status 未保存 同上
2026-05 变动记录筛选"出库"无效 前端 value 与后端期望值不匹配

开发纪律(MUST)

1. _row_to_dict 是单一真相源

CRUD 文件中的 _row_to_dict 函数定义了实体返回给前端的所有可读字段。它是字段一致性的基准。

2. 先写 _row_to_dict,再写 create/update

新增实体时:

  1. 先定义 _row_to_dict,列出所有字段的读取逻辑
  2. 根据 _row_to_dict 的字段列表,逐字段编写 CreateBody/UpdateBody
  3. 根据 Schema 字段,逐字段编写 create/update 函数签名和 ORM 赋值
  4. 根据后端字段列表,编写前端 formData

3. 排除只读字段

以下字段出现在 _row_to_dict 中但不需要出现在 CreateBody/UpdateBody 或 formData 中:

  • id — 自动生成
  • createTime / updateTime — 自动维护
  • stockQty — 通过出入库操作维护,不可直接设置
  • tenantNo — 从认证上下文获取

4. 每个字段必须检查的 5 个位置

以 warningQty 为例:

位置 代码 必须
_row_to_dict "warningQty": _dec(c.warning_qty) ✅ 读取
CreateBody warning_qty: Optional[float] = Field(0, alias="warningQty") ✅ 接收
Handler warning_qty=body.warning_qty ✅ 传递
create 函数签名 warning_qty: Optional[float] = None ✅ 接收
create ORM 赋值 warning_qty=warning_qty if warning_qty is not None else 0 ✅ 写入

5. 实现后验证

每个实体完成后运行:

python backend/scripts/check_field_consistency.py

检查项:

  • _row_to_dict 中的可写字段是否都在 CreateBody/UpdateBody 中
  • _row_to_dict 中的可写字段是否都在前端 formData 中
  • 前后端字段值映射是否一致(如筛选条件 value 对应关系)

校验脚本

backend/scripts/check_field_consistency.py 自动扫描以下三层,输出 diff 报告:

  1. CRUD 层:提取 _row_to_dict 的所有 camelCase key
  2. API 层:提取 CreateBody/UpdateBody 的所有字段(含 alias)
  3. 前端层:提取 formData 的所有 key

使用方式

# 检查所有注册实体
python backend/scripts/check_field_consistency.py

# 检查单个实体
python backend/scripts/check_field_consistency.py --entity consumable

# JSON 格式输出
python backend/scripts/check_field_consistency.py --json

退出码

  • 0:所有检查通过
  • 1:发现字段不一致

常见陷阱

  1. alias 遗漏:Schema 字段有 alias="warningQty" 但忘记写,Pydantic 只接受 snake_case 键名
  2. Handler 传参遗漏:Schema 有字段但 Handler 没传给 CRUD,字段在 Schema 层就被丢弃
  3. CRUD 签名遗漏:Handler 传了但 CRUD 函数签名没接收,Python 会报 unexpected keyword argument(运行时错误)
  4. 前端 value 与后端不匹配:如筛选条件下拉框的 value 是 "use" 但后端期望 "out"