[FIX] core: enable callable in api.constrains()

This avoids a call to __init__() which no longer has access to the
model's class' parent classes, and was not even correct...

closes odoo/odoo#70400

Related: odoo/enterprise#18141
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
This commit is contained in:
Raphael Collet
2021-05-06 07:30:29 +00:00
parent 35a9f6c27a
commit 3deafa8ebc
3 changed files with 15 additions and 4 deletions
+1 -4
View File
@@ -45,10 +45,7 @@ class SequenceMixin(models.AbstractModel):
field=sql.Identifier(self._sequence_field),
))
def __init__(self, pool, cr):
api.constrains(self._sequence_field, self._sequence_date_field)(type(self)._constrains_date_sequence)
return super().__init__(pool, cr)
@api.constrains(lambda self: (self._sequence_field, self._sequence_date_field))
def _constrains_date_sequence(self):
# Make it possible to bypass the constraint to allow edition of already messed up documents.
# /!\ Do not use this to completely disable the constraint as it will make this mixin unreliable.
+5
View File
@@ -127,7 +127,12 @@ def constrains(*args):
sure a constraint will always be triggered (e.g. to test the absence of
value).
One may also pass a single function as argument. In that case, the field
names are given by calling the function with a model instance.
"""
if args and callable(args[0]):
args = args[0]
return attrsetter('_constrains', args)
+9
View File
@@ -750,9 +750,18 @@ class BaseModel(metaclass=MetaModel):
def is_constraint(func):
return callable(func) and hasattr(func, '_constrains')
def wrap(func, names):
# wrap func into a proxy function with explicit '_constrains'
@api.constrains(*names)
def wrapper(self):
return func(self)
return wrapper
cls = type(self)
methods = []
for attr, func in getmembers(cls, is_constraint):
if callable(func._constrains):
func = wrap(func, func._constrains(self))
for name in func._constrains:
field = cls._fields.get(name)
if not field: