Add a contextual read limit for related fields

This commit is contained in:
Nicolas Évrard committed 2024-04-08 13:13:14 +02:00
1 parent c3a7758c5c
commit b973f371c8
5 files changed
+99 -1

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
* Add a contextual read limit for related fields
* Add xml_id field on ModelStorage
* Add send_message methods
* Store model on ir.rule.group
+3
View File
@@ -324,6 +324,9 @@ Class methods:
Their values will be returned under the referencing field suffixed by a
``.``.
The number of *dots* in the name is not limited.
The number of records read using *dots* can be limited with the
``related_read_limit`` key in the context.
The remaining records will only contain the ``id`` field.
``fields_names`` can also contain ``<field>:string`` for
:class:`~fields.Selection` or :class:`~fields.MultiSelection` fields.
+5 -1
View File
@@ -1213,7 +1213,11 @@ class ModelSQL(ModelStorage):
value = row[name]
if value is not None:
add(value)
return Target.read(target_ids, fields)
related_read_limit = transaction.context.get('related_read_limit')
rows = Target.read(target_ids[:related_read_limit], fields)
if related_read_limit is not None:
rows += [{'id': i} for i in target_ids[related_read_limit:]]
return rows
def add_related(field, rows, targets):
name = field.name
+24
View File
@@ -35,6 +35,28 @@ class ModelSQLReadContextID(ModelSQL):
})
class ModelSQLReadLimit(ModelSQL):
"ModelSQL to test related limit"
__name__ = 'test.modelsql.read.limit'
name = fields.Char("Name")
targets = fields.One2Many(
'test.modelsql.read.limit.target', 'parent', "Targets")
sum_targets = fields.Function(
fields.Integer("Sum of Targets"), 'on_change_with_sum_targets')
@fields.depends('targets')
def on_change_with_sum_targets(self, name=None):
return sum(t.integer for t in self.targets)
class ModelSQLReadLimitTarget(ModelSQL):
"ModelSQL to test related limit"
__name__ = 'test.modelsql.read.limit.target'
name = fields.Char("Name")
integer = fields.Integer("Integer")
parent = fields.Many2One('test.modelsql.read.limit', "Parent")
class ModelSQLRequiredField(ModelSQL):
'model with a required field'
__name__ = 'test.modelsql'
@@ -257,6 +279,8 @@ def register(module):
ModelSQLRead,
ModelSQLReadTarget,
ModelSQLReadContextID,
ModelSQLReadLimit,
ModelSQLReadLimitTarget,
ModelSQLRequiredField,
ModelSQLTimestamp,
ModelSQLCreate,
+66
View File
@@ -308,6 +308,72 @@ class ModelSQLTestCase(unittest.TestCase):
}],
}])
@with_transaction()
def test_read_limit(self):
"Test that we limit the number or related records read"
pool = Pool()
Model = pool.get('test.modelsql.read')
model, = Model.create([{
'name': 'Record',
'targets': [
('create', [{'name': str(i)} for i in range(10)]),
]
}])
values, = Model.read([model.id], ['targets.name'])
self.assertTrue(all('id' in t and 'name' in t
for t in values['targets.']))
with Transaction().set_context(related_read_limit=4):
values, = Model.read([model.id], ['targets.name'])
self.assertTrue(all('id' in t and 'name' in t
for t in values['targets.'][:4]))
self.assertTrue(all('id' in t and len(t) == 1
for t in values['targets.'][4:]))
@with_transaction()
def test_read_limit_only_limit_related(self):
"Test that we don't limit reading records with related_read_limit"
pool = Pool()
Model = pool.get('test.modelsql.read')
records = Model.create([
{
'name': f'Record {i}',
'targets': [
('create', [{'name': str(i)} for i in range(10)]),
]
} for i in range(10)])
with Transaction().set_context(related_read_limit=4):
values = Model.read(
[r.id for r in records], ['name', 'targets.name'])
self.assertTrue(all('id' in v and 'name' in v for v in values))
self.assertTrue(all(len(v['targets.']) == 10 for v in values))
@with_transaction()
def test_read_limit_caching(self):
"Test that limiting the related records read plays nice with caching"
pool = Pool()
Model = pool.get('test.modelsql.read.limit')
records = Model.create([
{
'name': f'Record {i}',
'targets': [
('create', [{'name': str(j), 'integer': j}
for j in range(1, i + 1)]),
],
} for i in range(10)])
with Transaction().set_context(read_limit=4):
values = Model.read(
[r.id for r in records],
['name', 'targets.name', 'sum_targets'])
computed = {r['name']: r['sum_targets'] for r in values}
expected = {f'Record {i}': i * (i + 1) // 2 for i in range(10)}
self.assertEqual(computed, expected)
@unittest.skipIf(backend.name == 'sqlite',
'SQLite not concerned because tryton don\'t set "NOT NULL"'
'constraint: "ALTER TABLE" don\'t support NOT NULL constraint'