Odoo中几种校验和约束的写法

Odoo中几种校验和约束的写法

  1. 逻辑校验

    顾名思义,我们可以在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
    @api.model
    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

    @api.multi
    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,逻辑判断时一定考虑清楚。

  2. 装饰器约束

    通过Odoo提供的api.constraints进行属性监控,这种监控主要针对于create和write时,vals中携带对应检测的字段时,才会触发。

    和1的逻辑校验类似的是,这里也可以通过自定义逻辑校验,可操作性也较强,但注意这里的self指代的是当前创建或者修改的记录,也就是说create时,当前记录在当前的cr中已经临时创建,即用self.idself.search([])或者self.env.cr.execute(f'select * from {self._table};') 都能查到当前记录,涉及判断的时候需要注意。

    1
    2
    3
    4
    5
    @api.constriants('name')
    def _check_test(self):
    for res in self:
    if res.name == 'a':
    raise ValidationError("@api.constriants('name') constriants error.")
  3. 数据库约束

    它实际通过源码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.")]
  4. 三者的优先级

    我们可以通过一下测试代码进行理解:

    如果 逻辑校验 定义在 create/write 的super之前,逻辑校验 > 数据库约束 > 装饰器约束。

    如果 逻辑校验 定义在 create/write 的super之后,数据库约束 > 装饰器约束 > 逻辑校验。

    image-20250606183020747 image-20250606182510909 image-20250606182653564
  5. 如果class有被继承,且使用inherit不是inherits方式,@api.constraints 将被子类默认使用,即使你没有在子类中定义相关api同名约束,就算定义了它也会先执行父级的@api.constraints方法,只不过把Self换成了子类的而不是父类的,这里有很多问题需要后续研究。

    image-20250606183619643