第 10 章:约束

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

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

SQL

参考:与此主题相关的文档可以在 模型PostgreSQL 文档 中找到。

注解

目标:在本节结束时:

  • 金额应为(严格)正数

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

名称约束

SQL 约束通过模型属性 _sql_constraints 定义。该属性被赋值为一个包含字符串三元组的列表 (name, sql_definition, message) ,其中 name 是有效的 SQL 约束名称, sql_definitiontable_constraint 表达式, message 是错误消息。

您可以在此处找到一个简单示例: 这里

Exercise

添加 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

可以在此处找到一个简单示例: 这里

Exercise

添加 Python 约束。

添加一个约束,使得销售价格不得低于预期价格的 90%。

提示:在报价被确认之前,销售价格为零。您需要对此进行微调以考虑这种情况。

警告

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

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

SQL 约束通常比 Python 约束更高效。当性能至关重要时,始终优先选择 SQL 约束而非 Python 约束。

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