From 499cdd57083da462eec0a66bf76be18a3c703101 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Thu, 22 Nov 2018 14:32:11 +0000 Subject: [FIX] fields: combine special values during onchange Consider a many2one field `foo_id` on model `bar`, with an inverse one2many field `bar_ids` on model `foo`. During an onchange, the statement bar.foo_id = foo puts a special value in cache to add `bar` to the value of `foo.bar_ids` without explicitly reading `foo.bar_ids`. Executing the above statement a second time, the cache of `foo.bar_ids` is no longer empty. This causes the actual value of `foo.bar_ids` to be read and updated. The issue is that this can be slow for large values of `foo.bar_ids`. Avoid reading the value of the one2many field by handling the case where the cache contains the special value: simply update the special value to take into account the second assignment. closes odoo/odoo#28982 --- odoo/addons/test_new_api/tests/test_onchange.py | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'odoo/addons/test_new_api/tests/test_onchange.py') diff --git a/odoo/addons/test_new_api/tests/test_onchange.py b/odoo/addons/test_new_api/tests/test_onchange.py index 1bfdee908a7..03cad7f4009 100644 --- a/odoo/addons/test_new_api/tests/test_onchange.py +++ b/odoo/addons/test_new_api/tests/test_onchange.py @@ -1,4 +1,8 @@ # -*- coding: utf-8 -*- +try: + from unittest.mock import patch +except ImportError: + from mock import patch from odoo.tests import common @@ -465,3 +469,32 @@ class TestOnChange(common.TransactionCase): result = Message.onchange(value, ['message', 'message_name', 'message_currency'], field_onchange) self.assertEqual(result['value'], onchange_result) + + def test_onchange_many2one_one2many(self): + """ Setting a many2one field should not read the inverse one2many. """ + discussion = self.env.ref('test_new_api.discussion_0') + field_onchange = self.Message._onchange_spec() + self.assertEqual(field_onchange.get('discussion'), '1') + + values = { + 'discussion': discussion.id, + 'name': "[%s] %s" % ('', self.env.user.name), + 'body': False, + 'author': self.env.uid, + 'size': 0, + } + + called = [False] + orig_read = type(discussion).read + + def mock_read(self, fields=None, load='_classic_read'): + if discussion in self and 'messages' in (fields or ()): + called[0] = True + return orig_read(self, fields, load) + + # changing 'discussion' on message should not read 'messages' on discussion + with patch.object(type(discussion), 'read', mock_read, create=True): + self.env.cache.invalidate() + self.Message.onchange(values, 'discussion', field_onchange) + + self.assertFalse(called[0], "discussion.messages has been read") -- cgit v1.2.3