From d10073d49608ca79e60cc0cb04076253facd046a Mon Sep 17 00:00:00 2001 From: Raphael Collet <rco@odoo.com> 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#78687 Signed-off-by: Raphael Collet (rco) <rco@openerp.com> --- 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 | 4 +++- 4 files changed, 24 insertions(+), 2 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 aa9aa4162e69..da4664a52a2b 100644 --- a/odoo/addons/test_new_api/models/test_new_api.py +++ b/odoo/addons/test_new_api/models/test_new_api.py @@ -345,6 +345,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): @@ -355,6 +356,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 a62bc669e69a..f39ee15f9636 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -1195,6 +1195,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 4404a9da2cb8..aa0325fe4f79 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 2ce567ec8b04..dcc9548848d8 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -480,7 +480,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, value in field.__dict__.items(): -- GitLab