Add a contextual read limit for related fields
This commit is contained in:
1 parent
c3a7758c5c
commit
b973f371c8
5 files changed
+99
-1
No files matched your search
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'
|
||||
|
||||
Reference in new issue
Block a user