[FIX] models: after extending a model, recompute its children models attributes
This is necessary when adding `_inherits`, `_depends` or constraints to a model.
This commit is contained in:
@@ -138,6 +138,8 @@ class Parent2(models.AbstractModel):
|
||||
|
||||
foo = fields.Integer()
|
||||
|
||||
_sql_constraints = [('unique_foo', 'UNIQUE(foo)', 'foo must be unique')]
|
||||
|
||||
def stuff(self):
|
||||
return super(Parent2, self).stuff() + 'P2'
|
||||
|
||||
|
||||
@@ -117,6 +117,12 @@ class TestInherit(common.TransactionCase):
|
||||
self.assertEqual(parent.stuff(), 'P1P2')
|
||||
self.assertEqual(child.stuff(), 'P1P2C1')
|
||||
|
||||
# check inferred model attributes
|
||||
self.assertEqual(parent._table, 'test_inherit_parent')
|
||||
self.assertEqual(child._table, 'test_inherit_child')
|
||||
self.assertEqual(len(parent._sql_constraints), 1)
|
||||
self.assertEqual(len(child._sql_constraints), 1)
|
||||
|
||||
# check properties memoized on model
|
||||
self.assertEqual(len(parent._constraint_methods), 1)
|
||||
self.assertEqual(len(child._constraint_methods), 1)
|
||||
|
||||
+41
-37
@@ -639,51 +639,55 @@ class BaseModel(object):
|
||||
else:
|
||||
bases.add(parent_class)
|
||||
parent_class._inherit_children.add(name)
|
||||
ModelClass.__bases__ = bases = tuple(bases)
|
||||
ModelClass.__bases__ = tuple(bases)
|
||||
|
||||
# determine the attributes of the model's class
|
||||
description = None
|
||||
table = None
|
||||
sequence = None
|
||||
log_access = ModelClass._auto
|
||||
inherits = {}
|
||||
depends = {}
|
||||
constraints = {}
|
||||
sql_constraints = []
|
||||
|
||||
for base in reversed(bases):
|
||||
if not getattr(base, 'pool', None):
|
||||
# the following attributes are not taken from model classes
|
||||
description = base._description or description
|
||||
table = base._table or table
|
||||
sequence = base._sequence or sequence
|
||||
log_access = getattr(base, '_log_access', log_access)
|
||||
|
||||
inherits.update(base._inherits)
|
||||
|
||||
for mname, fnames in base._depends.iteritems():
|
||||
depends[mname] = depends.get(mname, []) + fnames
|
||||
|
||||
for cons in base._constraints:
|
||||
# cons may override a constraint with the same function name
|
||||
constraints[getattr(cons[0], '__name__', id(cons[0]))] = cons
|
||||
|
||||
sql_constraints += base._sql_constraints
|
||||
|
||||
ModelClass._description = description or name
|
||||
ModelClass._table = table or name.replace('.', '_')
|
||||
ModelClass._sequence = sequence or (ModelClass._table + '_id_seq')
|
||||
ModelClass._log_access = log_access
|
||||
ModelClass._inherits = inherits
|
||||
ModelClass._depends = depends
|
||||
ModelClass._constraints = constraints.values()
|
||||
ModelClass._sql_constraints = sql_constraints
|
||||
ModelClass._build_model_attributes(pool)
|
||||
|
||||
# instantiate the model, and initialize it
|
||||
model = object.__new__(ModelClass)
|
||||
model.__init__(pool, cr)
|
||||
return model
|
||||
|
||||
@classmethod
|
||||
def _build_model_attributes(cls, pool):
|
||||
""" Initialize base model attributes. """
|
||||
cls._description = cls._name
|
||||
cls._table = cls._name.replace('.', '_')
|
||||
cls._sequence = None
|
||||
cls._log_access = cls._auto
|
||||
cls._inherits = {}
|
||||
cls._depends = {}
|
||||
cls._constraints = {}
|
||||
cls._sql_constraints = []
|
||||
|
||||
for base in reversed(cls.__bases__):
|
||||
if not getattr(base, 'pool', None):
|
||||
# the following attributes are not taken from model classes
|
||||
cls._description = base._description or cls._description
|
||||
cls._table = base._table or cls._table
|
||||
cls._sequence = base._sequence or cls._sequence
|
||||
cls._log_access = getattr(base, '_log_access', cls._log_access)
|
||||
|
||||
cls._inherits.update(base._inherits)
|
||||
|
||||
for mname, fnames in base._depends.iteritems():
|
||||
cls._depends[mname] = cls._depends.get(mname, []) + fnames
|
||||
|
||||
for cons in base._constraints:
|
||||
# cons may override a constraint with the same function name
|
||||
cls._constraints[getattr(cons[0], '__name__', id(cons[0]))] = cons
|
||||
|
||||
cls._sql_constraints += base._sql_constraints
|
||||
|
||||
cls._sequence = cls._sequence or (cls._table + '_id_seq')
|
||||
cls._constraints = cls._constraints.values()
|
||||
|
||||
# recompute attributes of children models
|
||||
for child_name in cls._inherit_children:
|
||||
child_class = type(pool[child_name])
|
||||
child_class._build_model_attributes(pool)
|
||||
|
||||
@classmethod
|
||||
def _init_function_fields(cls, pool, cr):
|
||||
# initialize the list of non-stored function fields for this model
|
||||
|
||||
Reference in New Issue
Block a user