details: https://code.tryton.org/tryton/commit/5e7086dc7cc4
branch: default
user: Nicolas Évrard <[email protected]>
date: Tue Apr 21 13:40:21 2026 +0200
description:
Fetch limit records of ResourceAccessMixin models when they are
available
Closes #14788
diffstat:
trytond/trytond/ir/resource.py | 35 +++++++++++++++++++++++++--------
trytond/trytond/tests/test_resource.py | 25 ++++++++++++++++++++++++
2 files changed, 51 insertions(+), 9 deletions(-)
diffs (85 lines):
diff -r 20e3adfa8812 -r 5e7086dc7cc4 trytond/trytond/ir/resource.py
--- a/trytond/trytond/ir/resource.py Mon Apr 20 17:03:34 2026 +0200
+++ b/trytond/trytond/ir/resource.py Tue Apr 21 13:40:21 2026 +0200
@@ -88,7 +88,12 @@
result = super().search(
domain, offset=offset, limit=limit, order=order,
count=False if enforce_access else count, query=query)
- if enforce_access:
+ if not enforce_access:
+ return result
+
+ loop = 0
+ fetched = []
+ while True:
records = result
resources = defaultdict(set)
allowed = set()
@@ -104,15 +109,27 @@
('id', 'in', ids),
]))
- records = [
+ fetched.extend([
r for r in records
- if not r.resource or r.resource in allowed]
- if count:
- result = len(records)
- else:
- # re-browse to have same context
- result = cls.browse(records)
- return result
+ if not r.resource or r.resource in allowed])
+
+ if limit is None or len(fetched) >= limit:
+ if limit is not None:
+ fetched = fetched[:limit]
+ break
+
+ loop += 1
+ result = super().search(
+ domain, offset=offset + loop * limit, limit=limit, order=order,
+ count=False, query=False)
+ if not result:
+ break
+
+ if count:
+ return len(fetched)
+ else:
+ # re-browse to have same context
+ return cls.browse(fetched)
@classmethod
def read(cls, ids, fields_names):
diff -r 20e3adfa8812 -r 5e7086dc7cc4 trytond/trytond/tests/test_resource.py
--- a/trytond/trytond/tests/test_resource.py Mon Apr 20 17:03:34 2026 +0200
+++ b/trytond/trytond/tests/test_resource.py Tue Apr 21 13:40:21 2026 +0200
@@ -235,3 +235,28 @@
Note.read([note.id], ['message'])
with self.assertRaises(AccessError):
Note.delete([note])
+
+ @with_transaction()
+ def test_resources_search_limit(self):
+ "Test resource search limit work as expected"
+ pool = Pool()
+ Note = pool.get('ir.note')
+ Warning_ = pool.get('res.user.warning')
+
+ warning1 = Warning_(user=0, name="root")
+ warning1.save()
+ warning2 = Warning_(user=1, name="admin")
+ warning2.save()
+ for i in range(100):
+ note = Note(resource=warning2 if i % 3 else warning1)
+ note.save()
+
+ with Transaction().set_context(_check_access=True):
+ notes = Note.search([], limit=10, offset=0)
+ self.assertEqual(len(notes), 10)
+
+ notes = Note.search([], limit=200, offset=0)
+ self.assertEqual(len(notes), 66)
+
+ notes = Note.search([])
+ self.assertEqual(len(notes), 66)