在前后端全链路开发中,一个字段需要同时出现在 5 个位置 才能完整打通:
前端 formData → API Schema (Pydantic) → API Handler 传参 → CRUD 函数签名 → ORM 赋值
任何一层遗漏都会导致字段静默丢失(Pydantic 默认忽略未定义字段,不报错),产生难以发现的 bug。
| 时间 | 问题 | 根因 |
|---|---|---|
| 2026-05 | 耗材/试剂新增时 warning_qty 未保存 |
Schema 缺字段 → Handler 没传 → CRUD 没接 |
| 2026-05 | 耗材/试剂新增时 status 未保存 |
同上 |
| 2026-05 | 变动记录筛选"出库"无效 | 前端 value 与后端期望值不匹配 |
_row_to_dict 是单一真相源CRUD 文件中的 _row_to_dict 函数定义了实体返回给前端的所有可读字段。它是字段一致性的基准。
_row_to_dict,再写 create/update新增实体时:
_row_to_dict,列出所有字段的读取逻辑_row_to_dict 的字段列表,逐字段编写 CreateBody/UpdateBody以下字段出现在 _row_to_dict 中但不需要出现在 CreateBody/UpdateBody 或 formData 中:
id — 自动生成createTime / updateTime — 自动维护stockQty — 通过出入库操作维护,不可直接设置tenantNo — 从认证上下文获取以 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 |
✅ 写入 |
每个实体完成后运行:
python backend/scripts/check_field_consistency.py
检查项:
_row_to_dict 中的可写字段是否都在 CreateBody/UpdateBody 中_row_to_dict 中的可写字段是否都在前端 formData 中backend/scripts/check_field_consistency.py 自动扫描以下三层,输出 diff 报告:
_row_to_dict 的所有 camelCase keyformData 的所有 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="warningQty" 但忘记写,Pydantic 只接受 snake_case 键名"use" 但后端期望 "out"检查器仅覆盖注册实体。material (market) 注册的 web-admin/src/views/market/material/index.vue 和 qc_material 注册的 web-admin/src/views/quality/material/index.vue 已失效;执行结果必须区分既有路径问题与本次改动,不能据检查器通过认定所有实体均已覆盖。