[FIX] base: don't crash during CRUD if record does not exist

- Let a model M define a Many2oneReference field F1.
- Let a model N define a One2many field F2 whose inverse is M->F1
- Define a computed field N->F3 that depends on N->F2

If, for whatever reason, a recordset of M contains records that have
been unlinked already and we try to unlink them again, the system will
crash with a MissingException error.

This happened because, while most _modified_trigger cases cover the case
of a MissingException (i.e. record not in cache), the case for a
Many2oneReference didn't.

This is fixed by simply ignoring these "stale" records in the
_modified_triggers section for Many2oneReference fields.

closes odoo/odoo#38816

X-original-commit: f3b05032f0576befda4dca870718afd429c21b0f
Signed-off-by: Adrian Torres (adt) <adt@odoo.com>
Co-authored-by: mreficent <miquel.raich@eficent.com>
This commit is contained in:
Adrian Torres
2019-10-15 14:33:07 +00:00
committed by fw-bot
co-authored by mreficent
parent b2a403efc7
commit 73b18b30b5
4 changed files with 40 additions and 2 deletions
@@ -42,3 +42,5 @@ access_test_new_api_model_child,access_test_new_api_model_child,model_test_new_a
access_test_new_api_model_child_nocheck,access_test_new_api_model_child_nocheck,model_test_new_api_model_child_nocheck,,1,1,1,1
access_test_new_api_display,access_test_new_api_display,model_test_new_api_display,,1,1,1,1
access_test_new_api_model_active_field,access_test_new_api_model_active_field,model_test_new_api_model_active_field,,1,1,1,1
access_test_new_api_model_many2one_reference,access_test_new_api_model_many2one_reference,model_test_new_api_model_many2one_reference,,1,1,1,1
access_test_new_api_inverse_m2o_ref,access_test_new_api_inverse_m2o_ref,model_test_new_api_inverse_m2o_ref,,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
42 access_test_new_api_model_child_nocheck access_test_new_api_model_child_nocheck model_test_new_api_model_child_nocheck 1 1 1 1
43 access_test_new_api_display access_test_new_api_display model_test_new_api_display 1 1 1 1
44 access_test_new_api_model_active_field access_test_new_api_model_active_field model_test_new_api_model_active_field 1 1 1 1
45 access_test_new_api_model_many2one_reference access_test_new_api_model_many2one_reference model_test_new_api_model_many2one_reference 1 1 1 1
46 access_test_new_api_inverse_m2o_ref access_test_new_api_inverse_m2o_ref model_test_new_api_inverse_m2o_ref 1 1 1 1
+21
View File
@@ -726,3 +726,24 @@ class ModelActiveField(models.Model):
parent_id = fields.Many2one('test_new_api.model_active_field')
children_ids = fields.One2many('test_new_api.model_active_field', 'parent_id')
parent_active = fields.Boolean(string='Active Parent', related='parent_id.active', store=True)
class ModelMany2oneReference(models.Model):
_name = 'test_new_api.model_many2one_reference'
_description = 'dummy m2oref model'
res_model = fields.Char('Resource Model')
res_id = fields.Many2oneReference('Resource ID', model_field='res_model')
class InverseM2oRef(models.Model):
_name = 'test_new_api.inverse_m2o_ref'
_description = 'dummy m2oref inverse model'
model_ids = fields.One2many('test_new_api.model_many2one_reference', 'res_id', string="Models")
model_ids_count = fields.Integer("Count", compute='_compute_model_ids_count')
@api.depends('model_ids')
def _compute_model_ids_count(self):
for rec in self:
rec.model_ids_count = len(rec.model_ids)
@@ -2001,3 +2001,15 @@ class TestRequiredMany2oneTransient(common.TransactionCase):
with self.assertRaises(ValueError):
field._setup_regular_base(Model)
@common.tagged('m2oref')
class TestMany2oneReference(common.TransactionCase):
def test_delete_m2o_reference_records(self):
m = self.env['test_new_api.model_many2one_reference']
self.env.cr.execute("SELECT max(id) FROM test_new_api_model_many2one_reference")
ids = self.env.cr.fetchone()
# fake record to emulate the unlink of a non-existant record
foo = m.browse(1 if not ids[0] else (ids[0] + 1))
self.assertTrue(foo.unlink())
+5 -2
View File
@@ -5571,8 +5571,11 @@ Record ids: %(records)s
if invf.type == 'many2one_reference':
rec_ids = set()
for rec in self:
if rec[invf.model_field] == key.model_name:
rec_ids.add(rec[invf.name])
try:
if rec[invf.model_field] == key.model_name:
rec_ids.add(rec[invf.name])
except MissingError:
continue
records = model.browse(rec_ids)
else:
try: