[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:
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user