From 60b0f6da3420e0bb0607bd73abb4d0a1f5a0a972 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Wed, 19 Feb 2020 11:25:15 +0000 Subject: [PATCH] [FIX] core: avoid invalidation of field 'ir.ui.view.arch' when setting it This fixes the following issue. Set the field `arch` on a view; this automatically writes on `arch_db`, which is a translated field. If some translations are discarded, a call to `unlink()` invalidates the whole cache. And then things go wrong: when `arch_db` is validated, the field `arch` is missing from cache, and the ORM sets it to `None` because the field is still protected by the initial write! Fix the issue by avoiding the call to `unlink()`, and do it in SQL instead. closes odoo/odoo#45740 X-original-commit: e7679152ee480a51ef2b6d208ae7a05b2ef61941 Signed-off-by: Raphael Collet (rco) --- odoo/addons/base/models/ir_translation.py | 9 +++++++- odoo/addons/base/tests/test_views.py | 26 +++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/odoo/addons/base/models/ir_translation.py b/odoo/addons/base/models/ir_translation.py index 9e9baa3a0e8..fa882102bd4 100644 --- a/odoo/addons/base/models/ir_translation.py +++ b/odoo/addons/base/models/ir_translation.py @@ -445,7 +445,14 @@ class IrTranslation(models.Model): # process outdated and discarded translations outdated.write({'state': 'to_translate'}) - discarded.unlink() + + if discarded: + # delete in SQL to avoid invalidating the whole cache + discarded._modified() + discarded.modified(self._fields) + self.flush(self._fields, discarded) + self.invalidate_cache(ids=discarded._ids) + self.env.cr.execute("DELETE FROM ir_translation WHERE id IN %s", [discarded._ids]) @api.model @tools.ormcache_context('model_name', keys=('lang',)) diff --git a/odoo/addons/base/tests/test_views.py b/odoo/addons/base/tests/test_views.py index 14e5786a937..a72fe32f2ad 100644 --- a/odoo/addons/base/tests/test_views.py +++ b/odoo/addons/base/tests/test_views.py @@ -236,6 +236,32 @@ class TestViewInheritance(ViewCase): 'arch': self.arch_for('itself', parent=True), }) + def test_write_arch(self): + self.env['res.lang']._activate_lang('fr_FR') + + v = self.makeView("T", arch='
Bar
') + self.env['ir.translation']._upsert_translations([{ + 'type': 'model_terms', + 'name': 'ir.ui.view,arch_db', + 'lang': 'fr_FR', + 'res_id': v.id, + 'src': 'Foo', + 'value': 'Fou', + }, { + 'type': 'model_terms', + 'name': 'ir.ui.view,arch_db', + 'lang': 'fr_FR', + 'res_id': v.id, + 'src': 'Bar', + 'value': 'Barre', + }]) + self.assertEqual(v.arch, '
Bar
') + + # modify v to discard translations; this should not invalidate 'arch'! + v.arch = '
' + self.assertEqual(v.arch, '
') + + class TestApplyInheritanceSpecs(ViewCase): """ Applies a sequence of inheritance specification nodes to a base architecture. IO state parameters (cr, uid, model, context) are used for