From aa0cdacced168f921e7ed389bab82d177ed21747 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Wed, 20 Oct 2021 09:09:49 +0000 Subject: [PATCH] [FIX] core: related field attributes A related field copies the attributes from its target field, except for the attributes defined on the related field itself. The implementation of this feature was not working properly for attributes with a truthy default value. closes odoo/odoo#79025 X-original-commit: dec4a7ec478fa02f19dee8c8426c88d17dc3c7f3 Signed-off-by: Raphael Collet (rco) --- odoo/addons/test_new_api/models/test_new_api.py | 3 +++ .../test_new_api/tests/test_new_fields.py | 17 +++++++++++++++++ odoo/addons/test_new_api/tests/test_schema.py | 2 +- odoo/fields.py | 8 ++++---- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/odoo/addons/test_new_api/models/test_new_api.py b/odoo/addons/test_new_api/models/test_new_api.py index 592b95db0d5..ddef5c09686 100644 --- a/odoo/addons/test_new_api/models/test_new_api.py +++ b/odoo/addons/test_new_api/models/test_new_api.py @@ -347,6 +347,7 @@ class Foo(models.Model): name = fields.Char() value1 = fields.Integer(change_default=True) value2 = fields.Integer() + text = fields.Char(trim=False) class Bar(models.Model): @@ -357,6 +358,8 @@ class Bar(models.Model): foo = fields.Many2one('test_new_api.foo', compute='_compute_foo', search='_search_foo') value1 = fields.Integer(related='foo.value1', readonly=False) value2 = fields.Integer(related='foo.value2', readonly=False) + text1 = fields.Char('Text1', related='foo.text', readonly=False) + text2 = fields.Char('Text2', related='foo.text', readonly=False, trim=True) @api.depends('name') def _compute_foo(self): diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py index 820f95497db..1223366053f 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -1198,6 +1198,23 @@ class TestFields(TransactionCaseWithUserDemo): discussion_field = discussion.fields_get(['name'])['name'] self.assertEqual(message_field['help'], discussion_field['help']) + def test_25_related_attributes(self): + """ test the attributes of related fields """ + text = self.registry['test_new_api.foo'].text + self.assertFalse(text.trim, "The target field is defined with trim=False") + + # trim=True is the default on the field's class + self.assertTrue(type(text).trim, "By default, a Char field has trim=True") + + # the parameter 'trim' is not set in text1's definition, so the field + # retrieves its value from text.trim + text1 = self.registry['test_new_api.bar'].text1 + self.assertFalse(text1.trim, "The related field retrieves trim=False from target") + + # text2 is defined with trim=True, so it should get that value + text2 = self.registry['test_new_api.bar'].text2 + self.assertTrue(text2.trim, "The related field was defined with trim=True") + def test_25_related_single(self): """ test related fields with a single field in the path. """ record = self.env['test_new_api.related'].create({'name': 'A'}) diff --git a/odoo/addons/test_new_api/tests/test_schema.py b/odoo/addons/test_new_api/tests/test_schema.py index ede1a790f96..90bdc1836b4 100644 --- a/odoo/addons/test_new_api/tests/test_schema.py +++ b/odoo/addons/test_new_api/tests/test_schema.py @@ -150,7 +150,7 @@ class TestSchema(common.TransactionCase): columns_data = self.get_columns_data('test_new_api_foo') self.assertEqual(set(columns_data), {'id', 'create_date', 'create_uid', 'write_date', - 'write_uid', 'name', 'value1', 'value2'}) + 'write_uid', 'name', 'value1', 'value2', 'text'}) # retrieve schema data about the table's foreign keys foreign_keys = self.get_foreign_keys('test_new_api_foo') diff --git a/odoo/fields.py b/odoo/fields.py index 6ef211e12a8..74e9d71cbc9 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -418,9 +418,7 @@ class Field(MetaField('DummyField', (object,), {})): if extra_keys: attrs['_extra_keys'] = extra_keys - for key, val in attrs.items(): - if getattr(self, key, Default) != val: - setattr(self, key, val) + self.__dict__.update(attrs) # prefetch only stored, column, non-manual and non-deprecated fields if not (self.store and self.column_type) or self.manual or self.deprecated: @@ -553,7 +551,9 @@ class Field(MetaField('DummyField', (object,), {})): # copy attributes from field to self (string, help, etc.) for attr, prop in self.related_attrs: - if not getattr(self, attr): + # check whether 'attr' is explicitly set on self (from its field + # definition), and ignore its class-level value (only a default) + if attr not in self.__dict__: setattr(self, attr, getattr(field, prop)) for attr in field._extra_keys: