第 10 章:约束

在 上一章 中,我们介绍了为模型添加业务逻辑的能力。现在我们可以将按钮关联到业务代码,但如何防止用户输入错误的数据呢?例如,在我们的房地产模块中,没有任何机制阻止用户设置负的期望价格。

Odoo 提供了两种设置自动校验不变量的方式:Python 约束 和 SQL 约束。

SQL

参考:与本主题相关的文档可在 型号 以及 PostgreSQL’s documentation 中找到。

注解

目标:本节结束时:

  • 金额应为(严格)正数

金额约束
  • 房产类型和标签的名称应唯一

名称约束

SQL 对象通过 Constraint 属性定义。

简单示例:

_check_percentage = models.Constraint(
    'CHECK(percentage >= 0 AND percentage <= 100)',
    'The percentage of an analytic distribution should be between 0 and 100.',
)

练习

添加 SQL 约束。

将以下约束添加到相应的模型中:

  • 房产的期望价格必须严格为正

  • 房产的售价必须为正

  • 报价价格必须严格为正

  • 房产标签名称和房产类型名称必须唯一

提示:在 Odoo 代码库中搜索 unique 关键字,以查找名称唯一的示例。

使用 -u estate 选项重启服务器以查看结果。请注意,你可能有一些数据会阻止设置 SQL 约束。可能会弹出类似下面的错误消息:

ERROR rd-demo odoo.schema: Table 'estate_property_offer': unable to add constraint 'estate_property_offer_check_price' as CHECK(price > 0)

例如,如果某些报价的价格为零,那么该约束就无法应用。你可以删除有问题的数据,以便应用新的约束。

Python

参考:与本主题相关的文档可在 constrains() 中找到。

注解

目标:本节结束时,将无法接受低于期望价格 90% 的报价。

Python 约束

SQL 约束是确保数据一致性的高效方式。但有时需要进行更复杂的检查,而这需要 Python 代码。在这种情况下,我们需要 Python 约束。

Python 约束定义为一个用 constrains() 装饰的方法,并在记录集上调用。该装饰器指定约束涉及哪些字段。当这些字段中的任何一个被修改时,约束会自动求值。如果不变量不满足,该方法应抛出异常:

from odoo.exceptions import ValidationError

...

@api.constrains('date_end')
def _check_date_end(self):
    for record in self:
        if record.date_end < fields.Date.today():
            raise ValidationError("The end date cannot be set in the past")
    # all records passed the test, don't return anything

一个简单的示例可参见 这里。

练习

添加 Python 约束。

添加一个约束,使售价不能低于期望价格的 90%。

提示:在报价被验证之前,售价为零。你需要细化检查以考虑这种情况。

警告

处理浮点数时,请始终使用来自 odoo.tools.float_utils 中的 float_compare() 和 float_is_zero() 方法!

确保每次售价或期望价格发生变化时都会触发该约束!

SQL 约束通常比 Python 约束更高效。在对性能有要求时,应始终优先选择 SQL 约束而非 Python 约束。

我们的房地产模块开始像样了。我们添加了一些业务逻辑,现在也确保了数据的一致性。然而,用户界面仍然有些粗糙。让我们在 下一章 中看看如何改进它。