[IMP] models: model extension may not change kind (abstract, model or transient)
This prevents a model extension from: - changing an abstract model to a non-abstract one, - changing a transient model to a non-transient one or vice-versa.
This commit is contained in:
+31
-1
@@ -307,7 +307,8 @@ class BaseModel(object):
|
||||
__metaclass__ = MetaModel
|
||||
_auto = False # don't create any database backend
|
||||
_register = False # not visible in ORM registry
|
||||
_transient = False # not transient
|
||||
_abstract = True # whether model is abstract
|
||||
_transient = False # whether model is transient
|
||||
|
||||
_name = None
|
||||
_columns = {}
|
||||
@@ -624,6 +625,8 @@ class BaseModel(object):
|
||||
if name not in pool:
|
||||
raise TypeError("Model %r does not exist in registry." % name)
|
||||
ModelClass = type(pool[name])
|
||||
ModelClass._build_model_check_base(cls)
|
||||
check_parent = ModelClass._build_model_check_parent
|
||||
else:
|
||||
ModelClass = type(name, (BaseModel,), {
|
||||
'_name': name,
|
||||
@@ -633,6 +636,7 @@ class BaseModel(object):
|
||||
'_fields': {}, # populated in _setup_base()
|
||||
'_defaults': {}, # populated in _setup_base()
|
||||
})
|
||||
check_parent = cls._build_model_check_parent
|
||||
|
||||
# determine all the classes the model should inherit from
|
||||
bases = LastOrderedSet([cls])
|
||||
@@ -644,6 +648,7 @@ class BaseModel(object):
|
||||
for base in parent_class.__bases__:
|
||||
bases.add(base)
|
||||
else:
|
||||
check_parent(cls, parent_class)
|
||||
bases.add(parent_class)
|
||||
parent_class._inherit_children.add(name)
|
||||
ModelClass.__bases__ = tuple(bases)
|
||||
@@ -656,6 +661,29 @@ class BaseModel(object):
|
||||
model.__init__(pool, cr)
|
||||
return model
|
||||
|
||||
@classmethod
|
||||
def _build_model_check_base(model_class, cls):
|
||||
""" Check whether ``model_class`` can be extended with ``cls``. """
|
||||
if model_class._abstract and not cls._abstract:
|
||||
msg = ("%s transforms the abstract model %r into a non-abstract model. "
|
||||
"That class should either inherit from AbstractModel, or set a different '_name'.")
|
||||
raise TypeError(msg % (cls, model_class._name))
|
||||
if model_class._transient != cls._transient:
|
||||
if model_class._transient:
|
||||
msg = ("%s transforms the transient model %r into a non-transient model. "
|
||||
"That class should either inherit from TransientModel, or set a different '_name'.")
|
||||
else:
|
||||
msg = ("%s transforms the model %r into a transient model. "
|
||||
"That class should either inherit from Model, or set a different '_name'.")
|
||||
raise TypeError(msg % (cls, model_class._name))
|
||||
|
||||
@classmethod
|
||||
def _build_model_check_parent(model_class, cls, parent_class):
|
||||
""" Check whether ``model_class`` can inherit from ``parent_class``. """
|
||||
if model_class._abstract and not parent_class._abstract:
|
||||
msg = ("In %s, the abstract model %r cannot inherit from the non-abstract model %r.")
|
||||
raise TypeError(msg % (cls, model_class._name, parent_class._name))
|
||||
|
||||
@classmethod
|
||||
def _build_model_attributes(cls, pool):
|
||||
""" Initialize base model attributes. """
|
||||
@@ -6252,6 +6280,7 @@ class Model(AbstractModel):
|
||||
"""
|
||||
_auto = True # automatically create database backend
|
||||
_register = False # not visible in ORM registry, meant to be python-inherited only
|
||||
_abstract = False # not abstract
|
||||
_transient = False # not transient
|
||||
|
||||
class TransientModel(Model):
|
||||
@@ -6264,6 +6293,7 @@ class TransientModel(Model):
|
||||
"""
|
||||
_auto = True # automatically create database backend
|
||||
_register = False # not visible in ORM registry, meant to be python-inherited only
|
||||
_abstract = False # not abstract
|
||||
_transient = True # transient
|
||||
|
||||
def itemgetter_tuple(items):
|
||||
|
||||
Reference in New Issue
Block a user