Skip to content

029. 数据模型序列化、命名转换与 Decimal ​

学习目标 ​

这一节继续完善后端 CRUD,并重点处理数据命名、序列化和数字精度。

学完后,你应该能理解:

  • 删除接口为什么也要先查数据;
  • 数据库表名和字段名为什么常用下划线;
  • 前端为什么更习惯驼峰命名;
  • 后端如何在下划线和驼峰之间转换;
  • Pydantic 的 model_dump、model_dump_json、model_validate 分别做什么;
  • PyCharm 工作目录为什么会影响 .env 读取;
  • 金额计算为什么要用 Decimal。

删除接口 ​

删除数据比新建和更新简单,但仍然要先查出来。

基本流程是:

  1. 根据 ID 查询记录;
  2. 如果记录不存在,返回错误或空结果;
  3. 调用 session 的 delete;
  4. 提交事务;
  5. 返回删除结果。

和更新一样,删除也不是直接拿前端传来的对象操作数据库。

数据库操作要围绕 session 中查出来的对象进行。

两种后端数据操作思路 ​

后端实现增删改查不只有 ORM 一种方式。

当前使用 SQLModel,属于 ORM 思路:用类和对象描述表和记录。

另一种常见方式是直接写 SQL。

例如 Java 里也有类似差异:

  • Spring JPA 更接近 ORM;
  • MyBatis 更接近直接写 SQL。

后续项目还会接触直接执行 SQL 的方式。直接 SQL 写起来可能更灵活,也更适合复杂通用查询,但封装难度会更高。

表名为什么要有前缀 ​

项目里的表名通常会有前缀。

前缀可以用来区分业务系统或数据来源。

例如:

  • pdd_user 可能表示拼多多同步过来的用户;
  • llm_ 开头可能表示大模型测试相关表;
  • pl_ 开头可能表示当前项目里的正式业务表。

真实企业里经常会有系统对接和数据同步。表名前缀能降低命名冲突,也能让人快速判断数据来自哪里。

数据库字段使用下划线命名 ​

数据库表名和字段名通常使用下划线命名。

例如:

txt
create_time
user_name
project_amount

原因包括:

  • 数据库命名习惯如此;
  • 避免和关键字冲突;
  • 跨语言更稳定;
  • SQL 里可读性更好。

Python 代码也通常使用下划线命名,这和数据库习惯一致。

前端更习惯驼峰命名 ​

前端 JS / TS 更习惯驼峰命名。

例如:

ts
createTime
userName
projectAmount

如果后端直接把数据库字段返回给前端,前端就会拿到下划线字段。

这会带来几个问题:

  • 前端类型不符合习惯;
  • 表单字段名不统一;
  • 组件封装更别扭;
  • 前后端命名规则混在一起。

所以后端需要在“数据库下划线”和“前端驼峰”之间做转换。

Pydantic 配置命名转换 ​

Pydantic 可以通过配置处理字段别名。

model 里可以配置:

  • 生成输出时使用驼峰名;
  • 接收输入时既允许原始字段名,也允许别名;
  • 忽略多余字段。

这样前端传 createTime,后端可以识别;数据库里仍然使用 create_time。

这层转换的目标是让不同层保持自己的命名规范,而不是互相污染。

忽略多余字段 ​

前端传参时可能带了一些后端 model 不认识的字段。

如果严格校验,可能直接报错。

有些场景下可以配置为忽略多余字段。

例如前端列表对象里带了 UI 状态字段,后端保存业务数据时不需要它。

但这不代表所有接口都应该随便忽略字段。对于安全敏感或严格业务接口,仍然要明确校验。

model_dump ​

Pydantic 的 model_dump 可以把 model 对象转成字典。

但默认情况下,它可能保留原字段名,也可能保留原始 Python 对象类型。

例如日期字段可能仍然是 datetime 对象,而不是前端需要的字符串。

如果直接返回这种对象,前端不一定能得到理想 JSON。

model_dump_json ​

model_dump_json 会把 model 转成 JSON 字符串,并处理一些类型转换。

配合字段别名参数,可以得到更适合返回给前端的数据:

  • 字段名变成驼峰;
  • 日期变成字符串;
  • 数字等类型按 JSON 规则输出。

后端返回给前端的数据,不能只看 Python 里能打印出来,还要看最终 JSON 长什么样。

封装 toDict ​

项目里会封装类似 toDict 的工具函数。

它的作用是统一把 model 对象转成前端需要的字典。

这样业务接口里不用每次手写:

  • 是否使用 alias;
  • 日期如何处理;
  • 是否排除空值;
  • 是否排除未设置字段。

统一工具函数能减少序列化差异。

model_validate ​

model_validate 可以把字典转换成 Pydantic / SQLModel 类实例。

转换过程中会做类型校验。

例如 model 要求 id 不能为空,但传入字典里没有 id,就会报校验错误。

这类错误能提前发现数据结构问题,而不是等写入数据库时才暴露。

项目里也可以封装一个 create 或类似工具函数,把字典转 model 的动作统一起来。

工作目录和 .env ​

PyCharm 里右键运行某个文件时,默认工作目录可能是这个文件所在目录。

如果代码里按相对路径读取 .env,就可能找不到项目根目录下的 .env。

解决方式是修改运行配置,把 Working Directory 设置成项目根目录。

这点很重要。

很多环境变量读取失败,不是 .env 写错,而是程序从错误目录开始找文件。

Decimal 和数字精度 ​

浮点数计算有精度问题。

经典例子是:

txt
0.1 + 0.2 !== 0.3

前端、Python、Java 等语言都会遇到类似问题。

涉及金额、积分、余额这类数据时,不能随便用普通浮点数做计算。

后端应该使用 Decimal 这类精确数字类型。

数据库 Decimal 类型 ​

数据库里也有 Decimal 类型。

它通常会声明:

  • 总位数;
  • 小数位数。

例如总共 30 位,其中小数 2 位。

后端 model 里的 Decimal 要和数据库字段类型对应起来。

这样从数据库读取数据、接收前端参数、进行后端计算时,都能避免普通浮点数带来的误差。

金额计算不要放在前端 ​

前端可以展示金额,但关键金额计算不应该依赖前端。

原因是:

  • 前端参数可以被篡改;
  • JS 浮点计算也有精度问题;
  • 业务责任最终在后端;
  • 数据入库前必须由后端校验和计算。

前端负责交互和展示,后端负责最终可信计算。

这一节的重点 ​

这一节把 CRUD 从“能跑”推进到“更像真实项目”。

你需要记住:

  • 删除也要先查记录;
  • 数据库用下划线,前端用驼峰;
  • 后端要做命名转换;
  • model 转 JSON 时要处理日期和别名;
  • 字典转 model 时要做校验;
  • PyCharm 工作目录会影响配置读取;
  • 金额和精确数字用 Decimal。

这些规范会直接影响后面通用表格、报销金额和 AI 业务数据的可靠性。

AI Agent 课程学习文档。