From 5fc9b8c44acc424f4e365b4d492dda93c03ddfcf Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Fri, 8 May 2020 08:36:08 +0000 Subject: [PATCH] [FIX] core: partial unlink in recordset The following loop crashes on the second iteration: for record in records: record.display_name # access non-stored computed field record.unlink() # delete record The cache has been invalidated by `unlink` on the first iteration, so the field is computed. The computation is done on the whole recordset, which fails with a `MissingError` because of the first record. The fix is to retry the recomputation on the single record in this case. closes odoo/odoo#50910 X-original-commit: 7f33ebf528b1415452ce549e3329c3fe89be0ad8 Signed-off-by: Raphael Collet (rco) --- odoo/addons/base/tests/test_orm.py | 18 ++++++++++++++++++ odoo/fields.py | 4 ++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/odoo/addons/base/tests/test_orm.py b/odoo/addons/base/tests/test_orm.py index 08ddd02b218..2e0406e6b5b 100644 --- a/odoo/addons/base/tests/test_orm.py +++ b/odoo/addons/base/tests/test_orm.py @@ -35,6 +35,24 @@ class TestORM(TransactionCase): # Deleting an already deleted record should be simply ignored self.assertTrue(p1.unlink(), "Re-deleting should be a no-op") + @mute_logger('odoo.models') + def test_access_partial_deletion(self): + """ Check accessing a record from a recordset where another record has been deleted. """ + Model = self.env['res.country'] + self.assertTrue(type(Model).display_name.automatic, "test assumption not satisfied") + + # access regular field when another record from the same prefetch set has been deleted + records = Model.create([{'name': name} for name in ('Foo', 'Bar', 'Baz')]) + for record in records: + record.name + record.unlink() + + # access computed field when another record from the same prefetch set has been deleted + records = Model.create([{'name': name} for name in ('Foo', 'Bar', 'Baz')]) + for record in records: + record.display_name + record.unlink() + @mute_logger('odoo.models', 'odoo.addons.base.models.ir_rule') def test_access_filtered_records(self): """ Verify that accessing filtered records works as expected for non-admin user """ diff --git a/odoo/fields.py b/odoo/fields.py index 23eb491b0bc..a958695b618 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -914,7 +914,7 @@ class Field(MetaField('DummyField', (object,), {})): recs = record if self.recursive else env.records_to_compute(self) try: self.compute_value(recs) - except AccessError: + except (AccessError, MissingError): self.compute_value(record) try: @@ -949,7 +949,7 @@ class Field(MetaField('DummyField', (object,), {})): recs = record if self.recursive else record._in_cache_without(self) try: self.compute_value(recs) - except AccessError: + except (AccessError, MissingError): self.compute_value(record) value = env.cache.get(record, self)