Odoo中几种校验和约束的写法
Odoo中几种校验和约束的写法
逻辑校验
顾名思义,我们可以在create/write方法中,添加对应的逻辑校验,这种检测理论上优先级最高,因为Jsonrpc调用保存逻辑后,首先进入执行的就是对应的create/write,但是为什么是理论上优先级最高。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def create(self, vals):
if vals.get('name', False) == 'a':
raise ValidationError("Create constriants up super error.")
res = super(TestConstraintsA, self).create(vals)
if vals.get('name', False) == 'a':
raise ValidationError("Create constriants up super error.")
return res
def write(self, vals):
if vals.get('name', False) == 'a':
raise ValidationError("Write constriants up super error.")
res = super(TestConstraintsA, self).write(vals)
for rec in self:
if rec.name == 'a':
raise ValidationError("Write constriants up super error.")
return res可以发现,在上述代码中,super前的校验肯定先走,如果你的校验约束写在了super后,那么不好意思,优先级就是最低的,低于后面要讲的2和3,因为2、3都是在super里执行的。
当然此种方式的可操作性更强,可自定义校验的能力较强,但注意create和write中的vals可能并不包含所使用值,尤其是write,逻辑判断时一定考虑清楚。
装饰器约束
通过Odoo提供的api.constraints进行属性监控,这种监控主要针对于create和write时,vals中携带对应检测的字段时,才会触发。
和1的逻辑校验类似的是,这里也可以通过自定义逻辑校验,可操作性也较强,但注意这里的self指代的是当前创建或者修改的记录,也就是说create时,当前记录在当前的cr中已经临时创建,即用
self.id
、self.search([])
或者self.env.cr.execute(f'select * from {self._table};')
都能查到当前记录,涉及判断的时候需要注意。1
2
3
4
5
def _check_test(self):
for res in self:
if res.name == 'a':
raise ValidationError("@api.constriants('name') constriants error.")数据库约束
它实际通过源码models.model中对应的插入(_create)/更新(_write)中的cr.execute(f”INSERT…) 、cr.execute(f”Update…)。
实际上它的原理是给数据库表上添加了对应的约束,通过数据库原生约束能力来进行实现。
它的操作性就不那么强了,因为它必须按照数据库约束的方式进行编写与定义,而且数据约束限制也很死板,抛错也是数据库红错。
1
2
3_sql_constraints = [("数据库约束名称","数据库约束","违反约束的报错")]
例如:
_sql_constraints = [("sql_constraints_unique_about_name","unique(name)","Name is unique.")]三者的优先级
我们可以通过一下测试代码进行理解:
如果 逻辑校验 定义在 create/write 的super之前,逻辑校验 > 数据库约束 > 装饰器约束。
如果 逻辑校验 定义在 create/write 的super之后,数据库约束 > 装饰器约束 > 逻辑校验。
如果class有被继承,且使用inherit不是inherits方式,@api.constraints 将被子类默认使用,即使你没有在子类中定义相关api同名约束,就算定义了它也会先执行父级的@api.constraints方法,只不过把Self换成了子类的而不是父类的,这里有很多问题需要后续研究。