From b9bfc0bb6e543be6985a9be78eba7531fa09f380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Voet=20=28ryv=29?= Date: Wed, 6 Mar 2024 14:45:35 +0000 Subject: [PATCH] [FIX] core: sorted of new records + prefetch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BaseModel's sorted() has two problems: - It breaks the prefetch of self for no reason - When it is called without an argument, it filters out new records because the search() used in sorted() doesn't return new records. Keep the same prefetch as self to fix the first problem. We partially fix/support the second issue, we just avoid filtering out new records (but we don't actually sort them) closes odoo/odoo#157145 X-original-commit: 0551c3b7e8e1469dabdb19d6420c544a1654fec5 Signed-off-by: Rémy Voet (ryv) --- odoo/addons/base/tests/test_api.py | 32 ++++++++++++++++++++++++++++++ odoo/models.py | 15 +++++++++----- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/odoo/addons/base/tests/test_api.py b/odoo/addons/base/tests/test_api.py index 8b2c81171f8..7a018fa1de4 100644 --- a/odoo/addons/base/tests/test_api.py +++ b/odoo/addons/base/tests/test_api.py @@ -670,6 +670,38 @@ class TestAPI(SavepointCaseWithUserDemo): by_name_ids = [p.id for p in sorted(ps, key=lambda p: p.name, reverse=True)] self.assertEqual(ps.sorted('name', reverse=True).ids, by_name_ids) + # sorted doesn't filter out new records but don't sort them either (limitation) + new_p = self.env['res.partner'].new({ + 'child_ids': [ + Command.create({'name': 'z'}), + Command.create({'name': 'a'}), + ], + }) + self.assertEqual(len(new_p.child_ids.sorted()), 2) + + # sorted keeps the _prefetch_ids + partners_with_children = self.env['res.partner'].create([ + { + 'name': 'required', + 'child_ids': [ + Command.create({'name': 'z'}), + Command.create({'name': 'a'}), + ], + }, + { + 'name': 'required', + 'child_ids': [ + Command.create({'name': 'z'}), + Command.create({'name': 'a'}), + ], + }, + ]) + partners_with_children.invalidate_model(['name']) + # Only one query to fetch name of children of each partner + with self.assertQueryCount(1): + for partner in partners_with_children: + partner.child_ids.sorted('id').mapped('name') + def test_group_on(self): p0, p1, p2 = self.env['res.partner'].create([ {'name': "bob", 'function': "guest"}, diff --git a/odoo/models.py b/odoo/models.py index 986ad27a86f..5ce03fa100c 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -6268,11 +6268,16 @@ class BaseModel(metaclass=MetaModel): records.sorted(key=lambda r: r.name) """ if key is None: - recs = self.search([('id', 'in', self.ids)]) - return self.browse(reversed(recs._ids)) if reverse else recs - if isinstance(key, str): - key = itemgetter(key) - return self.browse(item.id for item in sorted(self, key=key, reverse=reverse)) + if any(self._ids): + ids = self.search([('id', 'in', self.ids)])._ids + else: # Don't support new ids because search() doesn't work on new records + ids = self._ids + ids = tuple(reversed(ids)) if reverse else ids + else: + if isinstance(key, str): + key = itemgetter(key) + ids = tuple(item.id for item in sorted(self, key=key, reverse=reverse)) + return self.__class__(self.env, ids, self._prefetch_ids) def update(self, values): """ Update the records in ``self`` with ``values``. """