SQLModel 使用 Decimal 精确处理金额与财务数据:从 Field 配置到数据库存储的完整实践
ORM数据库后端【免费下载链接】sqlmodelSQL databases in Python, designed for simplicity, compatibility, and robustness.项目地址https://gitcode.com/gh_mirrors/sq/sqlmodel点击查看免费下载本指南以 SQLModel 官方文档 Decimal Numbers 为核心系统讲解如何在 SQLModel 模型中使用 Python 标准库decimal.Decimal类型来存储货币、价格、账户余额等对精度有严格要求的财务数据。读完本文你将掌握Field()中max_digits与decimal_places参数的精确配置规则、合法的数值范围判断方法以及 SQLModel 底层如何将Decimal映射为 SQLAlchemy 的DECIMAL/Numeric数据库列类型。为什么财务数据需要 Decimal在二进制计算机中浮点数float的存储方式决定了它无法精确表达所有十进制小数。以最常见的例子来说在 Python 中执行1.1 2.2直觉上应该得到3.3实际却得到 1.1 2.2 3.3000000000000003这是因为1.1和2.2在二进制中都是无限循环小数只能近似存储累加后误差便暴露出来。Python 提供了decimal标准库模块和Decimal类型来解决这类问题它可以以十进制的形式严格保存数值从而保证运算结果的确定性。数据库在底层同样以二进制存储数据因此也存在相同的问题这也正是主流数据库都提供专用decimal类型的原因。对多数场景如统计视频播放量、游戏角色血条来说浮点误差通常无关紧要但对于货币、价格、账户余额这类涉及金钱与财务计算的业务四舍五入误差是绝对不能接受的此时就必须使用 Decimal。SQLModel 中 Decimal 的类型基础Pydantic 对Decimal类型有专门支持。当你在 SQLModel 模型字段上使用Decimal时可以通过Field()函数指定该数值允许的总位数digits和小数位数decimal placesmax_digits数值允许的最大总位数同时包含整数部分和小数部分decimal_places小数点右侧允许的小数位数。这两个参数一方面由 Pydantic 在校验阶段例如配合 FastAPI 做请求体校验时强制执行另一方面会被 SQLModel 原样传递给数据库列定义让数据库层面的精度约束与模型层面的校验保持一致。从源码看SQLModel 的Field()签名完整接收max_digits与decimal_places两个参数见 sqlmodel/main.py并在构造字段信息时将其原样转发给底层 Pydantic 元数据见 sqlmodel/main.py。在内部兼容层中SQLModel 通过FakeMetadata类持有这两个属性供后续类型映射读取见 sqlmodel/_compat.py。底层数据库类型映射SQLModel 在将模型字段转换为数据库列时会通过get_sqlalchemy_type()函数完成 Python 类型到 SQLAlchemy 类型的映射。当字段类型是Decimal时映射逻辑如下见 sqlmodel/main.pyif issubclass(type_, Decimal): return Numeric( precisiongetattr(metadata, max_digits, None), scalegetattr(metadata, decimal_places, None), )也就是说SQLModel 使用 SQLAlchemy 的DECIMAL类型即Numeric来表示 Decimal 字段并将max_digits映射为 SQL 层面的precision精度将decimal_places映射为scale小数位。这意味着你在 Python 模型中声明的精度约束会直接体现在数据库表结构中形成端到端的精度保证。在模型中使用 Decimal 字段假设数据库中的每个 hero英雄都有一笔钱我们可以将该字段声明为Decimal并用Field()参数配置最大位数与小数位。完整示例代码如下见 docs_src/advanced/decimal/tutorial001_py310.pyfrom decimal import Decimal from sqlmodel import Field, Session, SQLModel, create_engine, select class Hero(SQLModel, tableTrue): id: int | None Field(defaultNone, primary_keyTrue) name: str Field(indexTrue) secret_name: str age: int | None Field(defaultNone, indexTrue) money: Decimal Field(default0, max_digits5, decimal_places3) sqlite_file_name database.db sqlite_url fsqlite:///{sqlite_file_name} engine create_engine(sqlite_url, echoTrue) def create_db_and_tables(): SQLModel.metadata.create_all(engine) def create_heroes(): hero_1 Hero(nameDeadpond, secret_nameDive Wilson, money1.1) hero_2 Hero(nameSpider-Boy, secret_namePedro Parqueador, money0.001) hero_3 Hero(nameRusty-Man, secret_nameTommy Sharp, age48, money2.2) with Session(engine) as session: session.add(hero_1) session.add(hero_2) session.add(hero_3) session.commit()其中money: Decimal Field(default0, max_digits5, decimal_places3)的含义是max_digits5money字段最多允许5 位数字这 5 位同时包括整数部分小数点左侧和小数部分小数点右侧decimal_places3小数点右侧最多3 位小数。因此该字段的整数部分最多只能是5 - 3 2位即数值范围为0到99.999之间考虑符号则为-99.999到99.999。合法的数值示例✅ 以下数值对money字段都是合法的12.345—— 5 位数字其中整数 2 位、小数 3 位12.3—— 不足 3 位小数时按 3 位小数存储即12.30012—— 无小数部分整数 2 位1.2—— 整数 1 位、小数 1 位0.123—— 整数 0 位、小数 3 位0—— 全零值。非法的数值示例 以下数值对money字段都是非法的1.2345—— 小数位数超过 3 位4 位小数123.234—— 总位数超过 5 位整数部分 3 位 小数部分 3 位123—— 虽然没有任何小数位但字段仍为小数保留了 3 位因此整数部分只能使用max_digits - decimal_places 2位而123有 3 位整数数字超出限制。提示请务必根据自己应用的实际业务需求调整位数和小数位配置。例如货币场景通常需要decimal_places2分而科学计算或高精度统计可能需要更多小数位。创建带 Decimal 字段的模型数据创建模型实例时你完全可以直接传入普通的float数字Pydantic 会自动将其转换为Decimal类型SQLModel 再通过 SQLAlchemy 以Decimal类型存入数据库。例如上面的示例代码中hero_1 Hero(nameDeadpond, secret_nameDive Wilson, money1.1) hero_2 Hero(nameSpider-Boy, secret_namePedro Parqueador, money0.001) hero_3 Hero(nameRusty-Man, secret_nameTommy Sharp, age48, money2.2)这里传入的1.1、0.001、2.2都是 Pythonfloat经过 Pydantic 校验后被规范化为Decimal(1.100)、Decimal(0.001)、Decimal(2.200)存储。注意1.1被自动补零为1.100以满足decimal_places3的精度约定。查询 Decimal 数据并验证精度写入数据之后再读取 Decimal 字段并参与运算即可验证它确实规避了浮点数的舍入误差def select_heroes(): with Session(engine) as session: statement select(Hero).where(Hero.name Deadpond) results session.exec(statement) hero_1 results.one() print(Hero 1:, hero_1) statement select(Hero).where(Hero.name Rusty-Man) results session.exec(statement) hero_2 results.one() print(Hero 2:, hero_2) total_money hero_1.money hero_2.money print(fTotal money: {total_money}) def main(): create_db_and_tables() create_heroes() select_heroes() if __name__ __main__: main()注意这里的hero_1.money hero_2.money是两个Decimal对象直接相加其结果依然是Decimal因此不会产生浮点累加误差。运行程序示例中使用了 uv 作为包管理器若你的环境不同可替换为python app.py$ uv run python app.py // 部分样板输出已省略 // The type of money is Decimal(1.100) Hero 1: id1 secret_nameDive Wilson ageNone nameDeadpond moneyDecimal(1.100) // 更多输出已省略 // The type of money is Decimal(1.100) Hero 2: id3 secret_nameTommy Sharp age48 nameRusty-Man moneyDecimal(2.200) // 没有舍入误差就是 3.3 Total money: 3.300可以看到最终输出是精确的3.300而不是浮点运算时出现的3.3000000000000003。这正是 Decimal 类型在财务计算中的核心价值。测试用例佐证仓库中的测试文件 tests/test_advanced/test_decimal/test_tutorial001.py 对上述行为做了完整验证。测试用内存型 SQLite 引擎sqlite://替换示例中的文件数据库然后运行示例的main()并断言Hero 1的money等于Decimal(1.100)Hero 2的money等于Decimal(2.200)两笔钱相加的结果打印为Total money: 3.300。这从自动化测试层面确认了从 Python 类型转换、数据库存取到算术运算Decimal 的精度在整个链路上都得到了保持。重要警告SQLite 不支持 Decimal虽然 Decimal 类型在 Python 侧得到完整支持但并非所有数据库都支持 Decimal 类型。需要特别注意的是SQLite 不支持 Decimal。在 SQLite 中Decimal 会被转换为它支持的浮点型NUMERIC类型这意味着精度保证在 SQLite 下无法落实。这一点在示例代码中也能得到印证——示例默认使用sqlite:///database.db作为数据库引擎因此实际的精度行为取决于底层数据库。好消息是绝大多数其他 SQL 数据库如 PostgreSQL、MySQL 等都原生支持 Decimal 类型在这些数据库上SQLModel 会以真正的DECIMAL(precision, scale)列来存储精度约束由数据库引擎强制执行。因此如果你的应用涉及金额等财务数据建议在生产环境选择支持 Decimal 的数据库并在部署前用真实数据库验证精度行为。实战要点总结何时使用 Decimal涉及货币、价格、账户余额、税率等对舍入误差敏感的财务场景一律使用Decimal普通计数、度量等场景使用float即可。字段声明方式money: Decimal Field(default0, max_digits5, decimal_places3)其中max_digits包含整数与小数全部位数整数部分上限为max_digits - decimal_places。写入无需手动转换创建模型时可以传floatPydantic 自动转换为Decimal并补足小数位。运算保持精确Decimal之间的加、减、乘、除不会引入浮点舍入误差适合直接用于财务计算。底层映射SQLModel 将Decimal映射为 SQLAlchemy 的Numeric/DECIMAL类型max_digits对应precision、decimal_places对应scale见 sqlmodel/main.py。数据库选型SQLite 会把 Decimal 降级为浮点NUMERIC精度无法保证生产环境请选用支持 Decimal 的 SQL 数据库。自动化验证可以参考 tests/test_advanced/test_decimal/test_tutorial001.py 的写法为财务字段编写精度断言测试防止回归。赞分享ORM数据库后端【免费下载链接】sqlmodelSQL databases in Python, designed for simplicity, compatibility, and robustness.项目地址https://gitcode.com/gh_mirrors/sq/sqlmodel点击查看免费下载相关推荐数据处理与存储从文件到数据库的完整流程数据处理与存储从文件到数据库的完整流程 本文全面探讨了数据处理与存储的完整技术流程涵盖了从序列号生成算法、MySQL关系型数据库操作、Redis非关系型数据SQLModel事务处理最佳实践确保数据一致性的完整方案SQLModel事务处理最佳实践确保数据一致性的完整方案 SQLModel作为Python中强大的ORM工具提供了完善的事务处理机制来保证数据库操作的数据一ORM数据库后端OpenPAI 数据管理完全指南从存储配置到任务使用OpenPAI 数据管理完全指南从存储配置到任务使用 前言 在OpenPAI深度学习平台中高效的数据管理是机器学习工作流的关键环节。本文将全面介绍如何在Op上一篇Android 12精确位置权限革命AndPermission新特性深度解析下一篇k-skill 的 lotto-results 技能与 k-lotto 包韩国 로또 6/45 开奖结果查询与号码大对照实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

AI前端核心能力:TypeScript构建SSE+WebSocket流式数据管道

AI前端核心能力:TypeScript构建SSE+WebSocket流式数据管道

1. 这不是“面试技巧”,而是AI时代前端工程师的生存切口“最后提醒一次,9月的AI前端面试不用太老实”——这句话在技术社区刷屏时,我正用TypeScript写一个SSE流式响应的错误重试逻辑。它听起来像一句调侃,但背后是真实到刺骨的行业…

2026/9/21 19:16:53 阅读更多 →
Voyager 仓库贡献避坑指南:从 PR 机制到插件系统的全链路实战手册

Voyager 仓库贡献避坑指南:从 PR 机制到插件系统的全链路实战手册

Voyager 仓库贡献避坑指南:从 PR 机制到插件系统的全链路实战手册 【免费下载链接】voyager Enhancement suite for Gemini, AI Studio, Claude & ChatGPT — plus a prompt manager for any websites, DeepSeek Harness included. / 面向 Gemini、AI Studio、C…

2026/9/21 19:15:53 阅读更多 →
CoffeeScript 2.0.0-beta1 变更详解:解构输出、Literate Markdown 解析与 get/set 调用约束

CoffeeScript 2.0.0-beta1 变更详解:解构输出、Literate Markdown 解析与 get/set 调用约束

CoffeeScript 2.0.0-beta1 变更详解:解构输出、Literate Markdown 解析与 get/set 调用约束 【免费下载链接】coffeescript Unfancy JavaScript 项目地址: https://gitcode.com/gh_mirrors/co/coffeescript 本篇以 2.0.0-beta1.md 为主线,系统梳理…

2026/9/21 19:15:53 阅读更多 →

最新新闻

OpenWiki实战指南:用开源自托管Wiki打造团队知识库

OpenWiki实战指南:用开源自托管Wiki打造团队知识库

不知道大家最近有没有注意到,技术社区和独立开发者的圈子里,关于OpenWiki的讨论越来越多。不只是程序员在自建知识库,连产品团队、运营小组、甚至一些做个人副业的朋友,都开始把它纳入自己的工具链。这背后肯定不只是“开源免费”…

2026/9/21 19:46:09 阅读更多 →
Swift 解 LeetCode 390:消除游戏的数学规律与 O(log n) 优化

Swift 解 LeetCode 390:消除游戏的数学规律与 O(log n) 优化

我第一次见“LeetCode 390 消除游戏”这道题的时候,第一反应是:这不就是模拟吗?维护一个数组,从左往右删一轮,再从右往左删一轮,循环到只剩一个数就完事。然后我看了眼数据范围,n 最大能到 10^9…

2026/9/21 19:46:09 阅读更多 →
地下城封号查询源码解析:3步搞定项目搭建

地下城封号查询源码解析:3步搞定项目搭建

地下城封号查询源码解析:3步搞定项目搭建 刚把Python语法背得滚瓜烂熟,一动手写个地下城封号查询接口,直接卡壳。 变量定义会了,函数也写了,怎么连数据库、怎么返回JSON,全懵圈。 这就是典型的“纸上谈兵”,懂原理却搭不起架子。…

2026/9/21 19:46:09 阅读更多 →
u支付高并发场景下性能优化完整示例与实战避坑指南

u支付高并发场景下性能优化完整示例与实战避坑指南

u支付高并发场景下性能优化完整示例与实战避坑指南 面试被问“为什么你的支付接口在高峰期会超时”,如果只能回答“加缓存”或“扩容”,基本就挂了。很多开发者对…

2026/9/21 19:46:09 阅读更多 →
3招搞定魔导英雄传安卓存档,避开高频面试题陷阱

3招搞定魔导英雄传安卓存档,避开高频面试题陷阱

3招搞定魔导英雄传安卓存档,避开高频面试题陷阱 刷过《魔导英雄传》安卓版的玩家都知道,想换个强力角色或者跳过前期枯燥的刷怪流程,改存档是最直接的办法。但很多人一上手就懵了,不是找不到文件,就是改完数据进游戏直接闪退,白白浪费了周末的时间。其…

2026/9/21 19:46:09 阅读更多 →
2026最新中国电子专利申请网源码解析:搞定报错堆栈的底层逻辑

2026最新中国电子专利申请网源码解析:搞定报错堆栈的底层逻辑

2026最新中国电子专利申请网源码解析:搞定报错堆栈的底层逻辑 盯着满屏红色的 StackTrace 崩溃日志,你是不是也一脸懵逼?明明照着 CSDN 上那些 2026 最新的教程敲代码,为什么一提交申请接口就抛出…

2026/9/21 19:45:09 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →