上一章介绍了向模型中添加一些业务逻辑的能力。我们现在可以将按钮链接到业务代码,但如何防止用户输入错误的数据?例如,在我们的房地产模块中,没有什么可以阻止用户设置负预期价格。
odoo提供了两种设置自动验证恒定式的方法:Python约束
and SQL约束
。
参考:与此主题相关的文档可以查看 Models 和PostgreSQL文档
(资料图片仅供参考)
我们通过模型属性_sql_constraints
来定义SQL约束,该属性被赋值为一个包含三元组(name, sql_definition, message)
的列表,其中name
为一个合法的SQL约束名称, sql_definition
为表约束表达式,message
为错误消息。
一个简单的示例。
class AccountAnalyticDistribution(models.Model): _name = "account.analytic.distribution" _description = "Analytic Account Distribution" _rec_name = "account_id" account_id = fields.Many2one("account.analytic.account", string="Analytic Account", required=True) percentage = fields.Float(string="Percentage", required=True, default=100.0) name = fields.Char(string="Name", related="account_id.name", readonly=False) tag_id = fields.Many2one("account.analytic.tag", string="Parent tag", required=True) _sql_constraints = [ ("check_percentage", "CHECK(percentage >= 0 AND percentage <= 100)", "The percentage of an analytic distribution should be between 0 and 100.") ]
一个简单的示例--唯一约束
class BlogTagCategory(models.Model): _name = "blog.tag.category" _description = "Blog Tag Category" _order = "name" name = fields.Char("Name", required=True, translate=True) tag_ids = fields.One2many("blog.tag", "category_id", string="Tags") _sql_constraints = [ ("name_uniq", "unique (name)", "Tag category already exists !"), ]
练习--添加SQL约束添加以下约束到对应模型:
房产预期价格必须为正数房产售价必须为正数报价必须为正数房产标签名称和类型名称必须唯一使用-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)
例如,如果某些报价的价格为零,则无法应用约束。可以删除、修正有问题的数据以应用新的约束。
修改odoo14\custom\estate\models\estate_property.py
,添加SQL约束
_sql_constraints = [ ("check_expected_price", "CHECK(expected_price > 0)", "expected price should be positive."), ("check_selling_price", "CHECK(selling_price > 0)", "selling price should be positive.") ]
注意:当selling_price为null
时,也通过CHECK(selling_price > 0)
校验的
修改odoo14\custom\estate\models\estate_property_tag.py
,添加SQL约束
_sql_constraints = [("check_tag", "unique(name)", "Tag name must be unique !")]
修改odoo14\custom\estate\models\estate_property_type.py
,添加SQL约束
_sql_constraints = [("check_name", "unique(name)", "Type name must be unique !")]
重启服务验证
预期效果动画:https://www.odoo.com/documentation/14.0/zh_CN/_images/sql_01.gif
https://www.odoo.com/documentation/14.0/zh_CN/_images/sql_02.gif
Python参考: 主题关联文档可查看constrains()
.
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
一个简单的示例。
@api.constrains("quantity") def check_quantity(self): for quant in self: if quant.location_id.usage != "inventory" and quant.lot_id and quant.product_id.tracking == "serial" \ and float_compare(abs(quant.quantity), 1, precision_rounding=quant.product_uom_id.rounding) > 0: raise ValidationError(_("The serial number has already been assigned: \n Product: %s, Serial Number: %s") % (quant.product_id.display_name, quant.lot_id.name))
练习--添加Python约束添加售价不能低于预期价格90%的约束
提示: 报价生效前,保持售价为0。你需要对校验进行微调,以便把这个考虑在内。
警告
当和浮点数打交道时,总是使用从
odoo.tools.float_utils
导入的float_compare()
和float_is_zero()
方法
确保每次售价或者预期价格改变时,自动触发约束
修改odoo14\custom\estate\models\estate_property.py
导入ValidationError
from odoo.exceptions import ValidationError
最末尾添加以下代码
@api.constrains("selling_price", "expected_price") def _check_selling_price(self): for record in self: if record.selling_price < self.expected_price * 0.9: raise ValidationError("selling price can`t not lower then 90 percent of expected price")
重启服务,浏览器中验证
预期效果动画:https://www.odoo.com/documentation/14.0/zh_CN/_images/python.gif
SQL约束通常比Python约束更效率。当性能很重要时,总是首选SQL约束而不是Python约束。
关键词: