From f9eeb3b44e2c89e14c035fafe147133d6a3eb040 Mon Sep 17 00:00:00 2001 From: Adrian Torres Date: Tue, 15 Oct 2019 13:07:03 +0000 Subject: [PATCH] [FIX] base: restrict m2o with ir models as inverses Before this revision, any m2o with an ir.* model as inverse could have the ondelete policy as 'restrict', either by default if it was required or by setting it explicitly in the field declaration. This is problematic because ir.* models are reflection models and they *MUST* be deleted during an uninstall of the module that introduces them, otherwise tables, fields, constraints, etc. are left in the database, this is why 'restrict' doesn't make sense UNLESS the unlink is being performed by an user and not by the system (uninstall). As a solution, this revision sets the default to cascade if the field is required, otherwise null. If the programmer explicitly sets a required m2o field with an ir.* model as an inverse to ondelete='restrict', it is considered an unsupported use-case and the registry will crash during loading with a clear error explaining that it is not supported. closes odoo/odoo#39739 Signed-off-by: Adrian Torres (adt) --- odoo/fields.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/odoo/fields.py b/odoo/fields.py index 3ada0e914ab..c56c67e08d6 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -35,6 +35,11 @@ EMPTY_DICT = frozendict() RENAMED_ATTRS = [('select', 'index'), ('digits_compute', 'digits')] DEPRECATED_ATTRS = [("oldname", "use an upgrade script instead.")] +IR_MODELS = ( + 'ir.model', 'ir.model.data', 'ir.model.fields', 'ir.model.fields.selection', + 'ir.model.relation', 'ir.model.constraint', 'ir.module.module', +) + _logger = logging.getLogger(__name__) _schema = logging.getLogger(__name__[:-7] + '.schema') @@ -2292,6 +2297,12 @@ class Many2one(_Relational): "as being 'set null'. Only 'restrict' and 'cascade' make sense." % (self.name, model._name) ) + if self.ondelete == 'restrict' and self.comodel_name in IR_MODELS: + raise ValueError( + f"Field {self.name} of model {model._name} is defined as ondelete='restrict' " + f"while having {self.comodel_name} as comodel, the 'restrict' mode is not " + f"supported for this type of field as comodel." + ) def update_db(self, model, columns): comodel = model.env[self.comodel_name]