From ea9ef7c39d3113b42de626e943425f7d63312c2f Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Wed, 26 Oct 2016 14:25:17 +0200 Subject: [PATCH] [FIX] base: prevent deletion of custom fields when other fields depend on them (#13978) Consider that you have a custom one2many field based on a custom many2one field, and that you delete the many2one field. From that point on, it is impossible to load the registry of the corresponding database. To prevent this from happening, we add a check before modifying or deleting custom fields. --- openerp/addons/base/ir/ir_model.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 1777982c75e..0b571bfcc06 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -142,6 +142,10 @@ class ir_model(osv.osv): if model.state != 'manual': raise UserError(_("Model '%s' contains module data and cannot be removed!") % (model.name,)) + # prevent screwing up fields that depend on these models' fields + for model in self.browse(cr, user, ids, context=context): + model.field_id._prepare_update() + self._drop_table(cr, user, ids, context) res = super(ir_model, self).unlink(cr, user, ids, context) if not context.get(MODULE_UNINSTALL_FLAG): @@ -431,6 +435,19 @@ class ir_model_fields(osv.osv): return True + @api.multi + def _prepare_update(self): + """ Check whether the fields in ``self`` may be modified or removed. + This method prevents the modification/deletion of many2one fields + that have an inverse one2many, for instance. + """ + for record in self: + model = self.env[record.model] + field = model._fields[record.name] + if field.type == 'many2one' and model._field_inverses.get(field): + msg = _("The field '%s' cannot be removed because the field '%s' depends on it.") + raise UserError(msg % (field, model._field_inverses[field][0])) + def unlink(self, cr, user, ids, context=None): # Prevent manual deletion of module columns if context is None: context = {} @@ -440,6 +457,9 @@ class ir_model_fields(osv.osv): any(field.state != 'manual' for field in self.browse(cr, user, ids, context)): raise UserError(_("This column contains module data and cannot be removed!")) + # prevent screwing up fields that depend on these fields + self.browse(cr, user, ids, context=context)._prepare_update() + self._drop_column(cr, user, ids, context) res = super(ir_model_fields, self).unlink(cr, user, ids, context) if not context.get(MODULE_UNINSTALL_FLAG): @@ -528,6 +548,7 @@ class ir_model_fields(osv.osv): if vals.get('name', item.name) != item.name: # We need to rename the column + item._prepare_update() if column_rename: raise UserError(_('Can only rename one field at a time!')) if vals['name'] in obj._fields: