先说结论
在 Odoo 里,很多人会把所有数据校验都想成“在 Python 里拦一下就行”。
但真正要理解清楚的是:
_sql_constraints- Python constraints
这两类约束虽然都在保护数据,却站在完全不同的边界层上。
最实用的理解是:
Python 约束更像业务层判断,SQL 约束更像数据库底线保护。
为什么这两个特别容易被混
因为它们表面都在做一件事:
- 不让坏数据进来
所以很多人会觉得:
- 既然 Python 能写,为什么还要数据库层?
但问题在于,系统真正需要的不只是“提示用户”,还包括:
- 数据在任何入口、任何并发情况下都不能突破的底线
这时数据库层和模型层就不是同一层责任了。
Python constraints 更像什么
它更像:
模型语义层的业务校验。
它特别适合:
- 跨字段业务逻辑判断
- 读起来更像业务规则的限制
- 需要更灵活表达的条件判断
所以它很适合表达“业务上不合理”。
_sql_constraints 更像什么
它更像:
数据库层不可突破的数据底线。
它特别适合:
- 唯一性
- 基础数值合法性
- 某些无论哪个入口都绝不能违反的硬约束
所以它的意义不只是“再写一遍规则”,而是把底线压到最靠近数据的那层去守。
为什么“能在 Python 里拦住”还不够
因为数据进入系统的入口不止一种:
- 表单
- 导入
- 自动化
- API
- 并发写入
如果你只在模型层或某条调用路径里拦,仍然可能留下边界缝隙。
这也是为什么真正涉及数据底线时,数据库层约束特别值钱。
为什么这不是“谁更高级”的问题
不是说 _sql_constraints 一定比 Python 约束高级,或反过来更灵活就更好。
更准确的理解是:
- 你到底想守的是业务语义
- 还是数据库绝不能破的底线
很多时候,两层都要有,但职责不同。
所以关键不是二选一,而是:
- 该把哪类规则放在哪一层。
实战里最容易踩的 5 个坑
1. 把所有规则都只写在 Python 层
底层完整性保护会不够硬。
2. 把复杂业务语义硬塞进 SQL 约束
可维护性会变差。
3. 以为两者只是写法不同
会低估边界层次差异。
4. 忽视并发和多入口写入场景
问题上线后才暴露。
5. 不先区分“业务不合理”和“数据绝不能存在”
规则设计会混乱。
一句话记忆法
把它记成一句话:
Python constraints 更像业务语义校验,
_sql_constraints更像数据库层底线保护;两者都在约束数据,但守的是不同层的边界。
理解这一句,数据约束设计会稳很多。
DISCUSSION
评论区