Skip to content

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

学习目标

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

学完后,你应该能理解:

  • 删除接口为什么也要先查数据;
  • 数据库表名和字段名为什么常用下划线;
  • 前端为什么更习惯驼峰命名;
  • 后端如何在下划线和驼峰之间转换;
  • Pydantic 的 model_dumpmodel_dump_jsonmodel_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 课程学习文档。