[FIX] models: make inverse of x2many fields work
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
access_test_unit,access_test_unit,model_test_unit,,1,1,1,1
|
||||
access_test_unit_line,access_test_unit_line,model_test_unit_line,,1,1,1,1
|
||||
access_test_box,access_test_box,model_test_box,,1,1,1,1
|
||||
access_test_pallet,access_test_pallet,model_test_pallet,,1,1,1,1
|
||||
access_test_another_unit,access_test_another_unit,model_test_another_unit,,1,1,1,1
|
||||
|
||||
|
@@ -11,6 +11,7 @@ class Unit(models.Model):
|
||||
name = fields.Char('Name', required=True)
|
||||
state = fields.Selection([('a', 'A'), ('b', 'B')], string='State')
|
||||
surname = fields.Char(compute='_compute_surname')
|
||||
line_ids = fields.One2many('test.unit.line', 'unit_id')
|
||||
|
||||
@api.depends('name')
|
||||
def _compute_surname(self):
|
||||
@@ -18,6 +19,14 @@ class Unit(models.Model):
|
||||
unit.surname = unit.name or ''
|
||||
|
||||
|
||||
class UnitLine(models.Model):
|
||||
_name = 'test.unit.line'
|
||||
_description = 'Test Unit Line'
|
||||
|
||||
name = fields.Char('Name', required=True)
|
||||
unit_id = fields.Many2one('test.unit', required=True)
|
||||
|
||||
|
||||
# We want to _inherits from the parent model and we add some fields
|
||||
# in the child object
|
||||
class Box(models.Model):
|
||||
|
||||
@@ -28,6 +28,26 @@ class test_inherits(common.TransactionCase):
|
||||
pallet.write({'name': 'C'})
|
||||
self.assertEqual(pallet.name, 'C')
|
||||
|
||||
def test_write_4_one2many(self):
|
||||
""" Check that we can write on an inherited one2many field. """
|
||||
box = self.env.ref('test_inherits.box_a')
|
||||
box.write({'line_ids': [(0, 0, {'name': 'Line 1'})]})
|
||||
self.assertTrue(all(box.line_ids._ids))
|
||||
self.assertEqual(box.line_ids.mapped('name'), ['Line 1'])
|
||||
self.assertEqual(box.line_ids, box.unit_id.line_ids)
|
||||
box.flush()
|
||||
box.invalidate_cache(['line_ids'])
|
||||
box.write({'line_ids': [(0, 0, {'name': 'Line 2'})]})
|
||||
self.assertTrue(all(box.line_ids._ids))
|
||||
self.assertEqual(box.line_ids.mapped('name'), ['Line 1', 'Line 2'])
|
||||
self.assertEqual(box.line_ids, box.unit_id.line_ids)
|
||||
box.flush()
|
||||
box.invalidate_cache(['line_ids'])
|
||||
box.write({'line_ids': [(1, box.line_ids[0].id, {'name': 'First line'})]})
|
||||
self.assertTrue(all(box.line_ids._ids))
|
||||
self.assertEqual(box.line_ids.mapped('name'), ['First line', 'Line 2'])
|
||||
self.assertEqual(box.line_ids, box.unit_id.line_ids)
|
||||
|
||||
def test_ir_model_data_inherits(self):
|
||||
""" Check the existence of the correct ir.model.data """
|
||||
IrModelData = self.env['ir.model.data']
|
||||
|
||||
+19
-1
@@ -3396,6 +3396,14 @@ Record ids: %(records)s
|
||||
for fname in vals:
|
||||
field = self._fields[fname]
|
||||
if field.inverse:
|
||||
if field.type in ('one2many', 'many2many'):
|
||||
# The written value is a list of commands that must applied
|
||||
# on the field's current value. Because the field is
|
||||
# protected while being written, the field's current value
|
||||
# will not be computed and default to an empty recordset. So
|
||||
# make sure the field's value is in cache before writing, in
|
||||
# order to avoid an inconsistent update.
|
||||
self[fname]
|
||||
determine_inverses[field.inverse].append(field)
|
||||
# DLE P150: `test_cancel_propagation`, `test_manufacturing_3_steps`, `test_manufacturing_flow`
|
||||
# TODO: check whether still necessary
|
||||
@@ -3403,7 +3411,17 @@ Record ids: %(records)s
|
||||
if field.relational or self._field_inverses[field]:
|
||||
relational_names.append(fname)
|
||||
if field.compute and not field.readonly:
|
||||
protected.update(self._field_computed.get(field, [field]))
|
||||
if field.store or field.type not in ('one2many', 'many2many'):
|
||||
# Protect the field from being recomputed while being
|
||||
# inversed. In the case of non-stored x2many fields, the
|
||||
# field's value may contain unexpeced new records (created
|
||||
# by command 0). Those new records are necessary for
|
||||
# inversing the field, but should no longer appear if the
|
||||
# field is recomputed afterwards. Not protecting the field
|
||||
# will automatically invalidate the field from the cache,
|
||||
# forcing its value to be recomputed once dependencies are
|
||||
# up-to-date.
|
||||
protected.update(self._field_computed.get(field, [field]))
|
||||
if fname == 'company_id' or (field.relational and field.check_company):
|
||||
check_company = True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user