From 2ea3c333e4b0a6e67c25147cfb0692b2e27c29cf Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Mon, 12 Mar 2018 11:43:14 +0100 Subject: [PATCH] [FIX] models: update non-stored inverse field on several records Issue: when the inverse method writes on a dependency of the first record, it invalidates the cache of the field for the other records... Solution: simply evaluate the inverse method one record at a time. --- .../test_new_api/tests/test_new_fields.py | 7 +++++++ odoo/models.py | 21 +++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py index df8f7ba4f2d..f0a086c989c 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -228,6 +228,13 @@ class TestFields(common.TransactionCase): self.assertEqual(ewan.parent, cath) self.assertEqual(ewan.name, "Erwan") + # write on non-stored inverse field on severals records + foo1 = Category.create({'name': 'Foo'}) + foo2 = Category.create({'name': 'Foo'}) + (foo1 + foo2).write({'display_name': 'Bar'}) + self.assertEqual(foo1.name, 'Bar') + self.assertEqual(foo2.name, 'Bar') + record = self.env['test_new_api.compute.inverse'] # create/write on 'foo' should only invoke the compute method diff --git a/odoo/models.py b/odoo/models.py index 4433286258c..a47fd56b0d7 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -3560,15 +3560,28 @@ class BaseModel(object): self._write(old_vals) if new_vals: - # put the values of pure new-style fields into cache, and inverse them self.modified(set(new_vals) - set(old_vals)) - for record in self: - record._cache.update(record._convert_to_cache(new_vals, update=True)) + + # put the values of fields into cache, and inverse them for key in new_vals: - self._fields[key].determine_inverse(self) + field = self._fields[key] + # If a field is not stored, its inverse method will probably + # write on its dependencies, which will invalidate the field + # on all records. We therefore inverse the field one record + # at a time. + batches = [self] if field.store else list(self) + for records in batches: + for record in records: + record._cache.update( + record._convert_to_cache(new_vals, update=True) + ) + field.determine_inverse(records) + self.modified(set(new_vals) - set(old_vals)) + # check Python constraints for inversed fields self._validate_fields(set(new_vals) - set(old_vals)) + # recompute new-style fields if self.env.recompute and self._context.get('recompute', True): self.recompute()