[FIX] web: fix the unity read with relational properties

Bug
===
Since 7d2baaa0c7 , we read the field
with `web_read`. We don't load the display name when calling read,
but instead we load them after.

But, since this change, the display names of the relational
properties are not loaded.

To fix that, we always load the display name of the relational
properties because it's a purely frontend field.

Task-3460126

Part-of: odoo/odoo#131394
This commit is contained in:
std-odoo
2023-08-28 16:42:03 +00:00
parent 1d4cbf99fd
commit 5a23c4dd1e
4 changed files with 55 additions and 38 deletions
@@ -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',
)
@@ -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'))
+11 -14
View File
@@ -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
+1 -1
View File
@@ -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