3.5 KiB
3.5 KiB
字段一致性开发指南
问题背景
在前后端全链路开发中,一个字段需要同时出现在 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
新增实体时:
- 先定义
_row_to_dict,列出所有字段的读取逻辑 - 根据
_row_to_dict的字段列表,逐字段编写 CreateBody/UpdateBody - 根据 Schema 字段,逐字段编写 create/update 函数签名和 ORM 赋值
- 根据后端字段列表,编写前端 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 报告:
- CRUD 层:提取
_row_to_dict的所有 camelCase key - API 层:提取 CreateBody/UpdateBody 的所有字段(含 alias)
- 前端层:提取
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:发现字段不一致
常见陷阱
- alias 遗漏:Schema 字段有
alias="warningQty"但忘记写,Pydantic 只接受 snake_case 键名 - Handler 传参遗漏:Schema 有字段但 Handler 没传给 CRUD,字段在 Schema 层就被丢弃
- CRUD 签名遗漏:Handler 传了但 CRUD 函数签名没接收,Python 会报 unexpected keyword argument(运行时错误)
- 前端 value 与后端不匹配:如筛选条件下拉框的 value 是
"use"但后端期望"out"