[FIX] core: cache consistency of one2many field with computed inverse
Consider a one2many field with a corresponding many2one field that is computed. After modifying the many2one field's dependencies, the cached value of the one2many field is inconsistent until the many2one field has been recomputed. Therefore, one has to force the computation of the many2one field before accessing the cached value of the one2many field. closes odoo/odoo#59034 X-original-commit: b9201ebdd65eaabab9257cf97c58410681783fa6 Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com> Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
This commit is contained in:
committed by
Raphael Collet
parent
0c7d16963b
commit
71549030c7
@@ -1127,3 +1127,23 @@ class ShareCacheComputeLine(models.Model):
|
||||
parent_id = fields.Many2one('test_new_api.model_shared_cache_compute_parent')
|
||||
amount = fields.Integer()
|
||||
user_id = fields.Many2one('res.users', default= lambda self: self.env.user) # Note: There is an ir.rule about this.
|
||||
|
||||
|
||||
class ComputeContainer(models.Model):
|
||||
_name = _description = 'test_new_api.compute.container'
|
||||
|
||||
name = fields.Char()
|
||||
member_ids = fields.One2many('test_new_api.compute.member', 'container_id')
|
||||
|
||||
|
||||
class ComputeMember(models.Model):
|
||||
_name = _description = 'test_new_api.compute.member'
|
||||
|
||||
name = fields.Char()
|
||||
container_id = fields.Many2one('test_new_api.compute.container', compute='_compute_container', store=True)
|
||||
|
||||
@api.depends('name')
|
||||
def _compute_container(self):
|
||||
container = self.env['test_new_api.compute.container']
|
||||
for member in self:
|
||||
member.container_id = container.search([('name', '=', member.name)], limit=1)
|
||||
|
||||
@@ -64,3 +64,5 @@ access_test_new_api_move,access_test_new_api_move,model_test_new_api_move,,1,1,1
|
||||
access_test_new_api_move_line,access_test_new_api_move_line,model_test_new_api_move_line,,1,1,1,1
|
||||
access_test_new_api_model_shared_cache_compute_parent,access_test_new_api.model_shared_cache_compute_parent,model_test_new_api_model_shared_cache_compute_parent,,1,1,1,1
|
||||
access_test_new_api_model_shared_cache_compute_line,access_test_new_api.model_shared_cache_compute_line,model_test_new_api_model_shared_cache_compute_line,,1,1,1,1
|
||||
access_test_new_api_compute_container,access_test_new_api_compute_container,model_test_new_api_compute_container,,1,1,1,1
|
||||
access_test_new_api_compute_member,access_test_new_api_compute_member,model_test_new_api_compute_member,,1,1,1,1
|
||||
|
||||
|
@@ -247,3 +247,11 @@ class One2manyCase(TransactionCase):
|
||||
# delete parent, and check that recomputation ends
|
||||
parent.unlink()
|
||||
parent.flush()
|
||||
|
||||
def test_compute_stored_many2one_one2many(self):
|
||||
container = self.env['test_new_api.compute.container'].create({'name': 'Foo'})
|
||||
self.assertFalse(container.member_ids)
|
||||
member = self.env['test_new_api.compute.member'].create({'name': 'Foo'})
|
||||
# at this point, member.container_id must be computed for member to
|
||||
# appear in container.member_ids
|
||||
self.assertEqual(container.member_ids, member)
|
||||
|
||||
@@ -3055,6 +3055,15 @@ class One2many(_RelationalMulti):
|
||||
domain = domain + [(inverse_field.model_field, '=', records._name)]
|
||||
return domain
|
||||
|
||||
def __get__(self, records, owner):
|
||||
if records is not None and self.inverse_name is not None:
|
||||
# force the computation of the inverse field to ensure that the
|
||||
# cache value of self is consistent
|
||||
inverse_field = records.pool[self.comodel_name]._fields[self.inverse_name]
|
||||
if inverse_field.compute:
|
||||
records.env[self.comodel_name].recompute([self.inverse_name])
|
||||
return super().__get__(records, owner)
|
||||
|
||||
def read(self, records):
|
||||
# retrieve the lines in the comodel
|
||||
context = {'active_test': False}
|
||||
|
||||
Reference in New Issue
Block a user