diff --git a/odoo/addons/test_new_api/tests/test_properties.py b/odoo/addons/test_new_api/tests/test_properties.py index 525af4240fd..5a2efd3f5a9 100644 --- a/odoo/addons/test_new_api/tests/test_properties.py +++ b/odoo/addons/test_new_api/tests/test_properties.py @@ -646,14 +646,6 @@ class PropertiesCase(TestPropertiesMixin): msg='Definition must be present when reading child') self.assertEqual(many2one_property['value'], (self.partner.id, self.partner.display_name)) - # disable the display_name - properties_values = (self.message_1 | self.message_3).read(['attributes'], load=None) - many2one_property = properties_values[0]['attributes'][1] - - self.assertEqual( - many2one_property['value'], self.partner.id, - msg='If display_name is disable, should only return the record id') - def test_properties_field_many2one_basic(self): """Test the basic (read, write...) of the many2one property.""" self.message_2.attributes = [ @@ -1065,6 +1057,9 @@ class PropertiesCase(TestPropertiesMixin): 'comodel': 'test_new_api.partner', }] + def name_get(records): + return list(zip(records._ids, records.mapped('display_name'))) + with self.assertQueryCount(4): self.message_1.attributes = [ { @@ -1075,18 +1070,18 @@ class PropertiesCase(TestPropertiesMixin): "value": list(zip(partners[:10]._ids, partners[:10].mapped('display_name'))), } ] - attributes = self.message_1.read(['attributes'], load=None)[0]['attributes'] - self.assertEqual(attributes[0]['value'], partners[:10].ids) + attributes = self.message_1.read(['attributes'])[0]['attributes'] + self.assertEqual(attributes[0]['value'], name_get(partners[:10])) partners[:5].unlink() - with self.assertQueryCount(4): - attributes = self.message_1.read(['attributes'], load=None)[0]['attributes'] - self.assertEqual(attributes[0]['value'], partners[5:10].ids) + with self.assertQueryCount(5): + attributes = self.message_1.read(['attributes'])[0]['attributes'] + self.assertEqual(attributes[0]['value'], name_get(partners[5:10])) partners[5].unlink() with self.assertQueryCount(5): properties = self.message_1.read(['attributes'])[0]['attributes'] - self.assertEqual(properties[0]['value'], list(zip(partners[6:10]._ids, partners[6:10].mapped('display_name')))) + self.assertEqual(properties[0]['value'], name_get(partners[6:10])) # need to wait next write to clean data in database # a single read won't clean the removed many2many @@ -1097,14 +1092,6 @@ class PropertiesCase(TestPropertiesMixin): sql_values = self._get_sql_properties(self.message_1) self.assertEqual(sql_values, {'moderator_partner_ids': partners[6:10].ids}) - # read and disable display_name - properties = self.message_1.read(['attributes'], load=None)[0]['attributes'] - self.assertEqual( - properties[0]['value'], - partners[6:10].ids, - msg='Should not return the partners name', - ) - # Check that duplicated ids are removed self.env.flush_all() moderator_partner_ids = partners[6:10].ids @@ -1122,7 +1109,7 @@ class PropertiesCase(TestPropertiesMixin): properties = self.message_1.read(['attributes'], load=None)[0]['attributes'] self.assertEqual( properties[0]['value'], - partners[6:10].ids, + name_get(partners[6:10]), msg='Should removed duplicated ids', ) diff --git a/odoo/addons/test_new_api/tests/test_unity_read.py b/odoo/addons/test_new_api/tests/test_unity_read.py index b9c97d495b0..b7fd4138083 100644 --- a/odoo/addons/test_new_api/tests/test_unity_read.py +++ b/odoo/addons/test_new_api/tests/test_unity_read.py @@ -755,3 +755,36 @@ class TestUnityRead(TransactionCase): 'm2o_reference_model': False, } ]) + + def test_properties(self): + """Check that the display name of the relational properties are always loaded.""" + discussion = self.env['test_new_api.discussion'].create({ + 'name': 'Test Discussion', + 'attributes_definition': [{ + 'name': 'discussion_color_code', + 'string': 'Color Code', + 'type': 'char', + 'default': 'blue', + }, { + 'name': 'moderator_partner_id', + 'string': 'Partner', + 'type': 'many2one', + 'comodel': 'test_new_api.partner', + }], + 'participants': [Command.link(self.env.user.id)], + }) + partner = self.env['test_new_api.partner'].create({'name': 'Test Partner Properties'}) + message = self.env['test_new_api.message'].create({ + 'name': 'Test Message', + 'discussion': discussion.id, + 'author': self.env.user.id, + 'attributes': { + 'discussion_color_code': 'Test', + 'moderator_partner_id': partner.id, + }, + }) + values = message.web_read({'attributes': False})[0]['attributes'] + self.assertEqual(len(values), 2) + self.assertEqual(values[0]['name'], 'discussion_color_code') + self.assertEqual(values[1]['name'], 'moderator_partner_id') + self.assertEqual(values[1]['value'], (partner.id, 'Test Partner Properties')) diff --git a/odoo/fields.py b/odoo/fields.py index 32a25080f2b..a311a99385a 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -11,6 +11,7 @@ from xmlrpc.client import MAXINT import ast import base64 import copy +import contextlib import binascii import enum import itertools @@ -3334,9 +3335,9 @@ class Properties(Field): # }] # def convert_to_read(self, value, record, use_display_name=True): - return self.convert_to_read_multi([value], record, use_display_name)[0] + return self.convert_to_read_multi([value], record)[0] - def convert_to_read_multi(self, values, records, use_display_name=True): + def convert_to_read_multi(self, values, records): if not records: return values assert len(values) == len(records) @@ -3351,15 +3352,14 @@ class Properties(Field): assert isinstance(value, dict), f"Wrong type {value!r}" result.append(self._dict_to_list(value, definition)) - res_ids_per_model = self._get_res_ids_per_model(records, result, use_display_name) + res_ids_per_model = self._get_res_ids_per_model(records, result) # value is in record format for value in result: self._parse_json_types(value, records.env, res_ids_per_model) - if use_display_name: - for value in result: - self._add_display_name(value, records.env) + for value in result: + self._add_display_name(value, records.env) return result @@ -3382,7 +3382,7 @@ class Properties(Field): record._cache[self.definition_record] = snapshot[self.definition_record].id or None return super().convert_to_onchange(value, record, names) - def _get_res_ids_per_model(self, records, values_list, use_display_name=True): + def _get_res_ids_per_model(self, records, values_list): """Read everything needed in batch for the given records. To retrieve relational properties names, or to check their existence, @@ -3419,13 +3419,10 @@ class Properties(Field): recs = records.env[model].browse(ids).exists() res_ids_per_model[model] = set(recs.ids) - if use_display_name: - for record in recs: - # read a field to pre-fetch the recordset - try: - record.display_name - except AccessError: - pass + for record in recs: + # read a field to pre-fetch the recordset + with contextlib.suppress(AccessError): + record.display_name return res_ids_per_model diff --git a/odoo/models.py b/odoo/models.py index 7f20801c79c..15304a99f0c 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -3369,7 +3369,7 @@ class BaseModel(metaclass=MetaModel): except MissingError: vals.clear() - results = field.convert_to_read_multi(values_list, self.browse(records), use_display_name) + results = field.convert_to_read_multi(values_list, self.browse(records)) for record_read_vals, convert_result in zip(data, results): record_read_vals[1][name] = convert_result continue