[FIX] models: compute-onchange
This commit is contained in:
@@ -23,6 +23,7 @@ access_test_new_api_compute_protected,access_test_new_api_compute_protected,mode
|
||||
access_test_new_api_multi_compute_inverse,access_test_new_api_multi_compute_inverse,model_test_new_api_multi_compute_inverse,,1,1,1,1
|
||||
access_test_new_api_recursive,access_test_new_api_recursive,model_test_new_api_recursive,,1,1,1,1
|
||||
access_test_new_api_cascade,access_test_new_api_cascade,model_test_new_api_cascade,,1,1,1,1
|
||||
access_test_new_api_compute_onchange,access_test_new_api_compute_onchange,model_test_new_api_compute_onchange,,1,1,1,1
|
||||
access_test_new_api_binary_svg,access_test_new_api_binary_svg,model_test_new_api_binary_svg,,1,1,1,1
|
||||
access_test_new_api_monetary_base,access_test_new_api_monetary_base,model_test_new_api_monetary_base,,1,1,1,1
|
||||
access_test_new_api_monetary_related,access_test_new_api_monetary_related,model_test_new_api_monetary_related,,1,1,1,1
|
||||
|
||||
|
@@ -373,8 +373,8 @@ class Related(models.Model):
|
||||
related_related_name = fields.Char(related='related_name', string='A related on a related on Name', readonly=False)
|
||||
|
||||
message = fields.Many2one('test_new_api.message')
|
||||
message_name = fields.Text(related="message.body", related_sudo=False, string='Message Body', readonly=False)
|
||||
message_currency = fields.Many2one(related="message.author", string='Message Author', readonly=False)
|
||||
message_name = fields.Text(related="message.body", related_sudo=False, string='Message Body')
|
||||
message_currency = fields.Many2one(related="message.author", string='Message Author')
|
||||
|
||||
class ComputeProtected(models.Model):
|
||||
_name = 'test_new_api.compute.protected'
|
||||
@@ -495,6 +495,27 @@ class ComputeCascade(models.Model):
|
||||
record.baz = "<%s>" % (record.bar or "")
|
||||
|
||||
|
||||
class ComputeOnchange(models.Model):
|
||||
_name = 'test_new_api.compute.onchange'
|
||||
_description = "Compute method as an onchange"
|
||||
|
||||
active = fields.Boolean()
|
||||
foo = fields.Char()
|
||||
bar = fields.Char(compute='_compute_bar', store=True)
|
||||
baz = fields.Char(compute='_compute_baz', store=True, readonly=False)
|
||||
|
||||
@api.depends('foo')
|
||||
def _compute_bar(self):
|
||||
for record in self:
|
||||
record.bar = record.foo
|
||||
|
||||
@api.depends('active', 'foo')
|
||||
def _compute_baz(self):
|
||||
for record in self:
|
||||
if record.active:
|
||||
record.baz = record.foo
|
||||
|
||||
|
||||
class ModelImage(models.Model):
|
||||
_name = 'test_new_api.model_image'
|
||||
_description = 'Test Image field'
|
||||
|
||||
@@ -522,3 +522,156 @@ class TestOnChange(common.TransactionCase):
|
||||
self.Message.onchange(values, 'discussion', field_onchange)
|
||||
|
||||
self.assertFalse(called[0], "discussion.messages has been read")
|
||||
|
||||
|
||||
class TestComputeOnchange(common.TransactionCase):
|
||||
|
||||
def test_create(self):
|
||||
model = self.env['test_new_api.compute.onchange']
|
||||
|
||||
# compute 'bar' and 'baz'
|
||||
record = model.create({'active': True, 'foo': "foo"})
|
||||
self.assertEqual(record.bar, "foo")
|
||||
self.assertEqual(record.baz, "foo")
|
||||
|
||||
# compute 'bar' but not 'baz'
|
||||
record = model.create({'active': True, 'foo': "foo", 'bar': "bar", 'baz': "baz"})
|
||||
self.assertEqual(record.bar, "foo")
|
||||
self.assertEqual(record.baz, "baz")
|
||||
|
||||
# compute 'bar' and 'baz', but do not change its value
|
||||
record = model.create({'active': False, 'foo': "foo"})
|
||||
self.assertEqual(record.bar, "foo")
|
||||
self.assertEqual(record.baz, False)
|
||||
|
||||
# compute 'bar' but not 'baz'
|
||||
record = model.create({'active': False, 'foo': "foo", 'bar': "bar", 'baz': "baz"})
|
||||
self.assertEqual(record.bar, "foo")
|
||||
self.assertEqual(record.baz, "baz")
|
||||
|
||||
def test_write(self):
|
||||
model = self.env['test_new_api.compute.onchange']
|
||||
record = model.create({'active': True, 'foo': "foo"})
|
||||
self.assertEqual(record.bar, "foo")
|
||||
self.assertEqual(record.baz, "foo")
|
||||
|
||||
# recompute 'bar' and 'baz'
|
||||
record.write({'foo': "foo1"})
|
||||
self.assertEqual(record.bar, "foo1")
|
||||
self.assertEqual(record.baz, "foo1")
|
||||
|
||||
# recompute 'bar' but not 'baz'
|
||||
record.write({'foo': "foo2", 'bar': "bar2", 'baz': "baz2"})
|
||||
self.assertEqual(record.bar, "foo2")
|
||||
self.assertEqual(record.baz, "baz2")
|
||||
|
||||
# recompute 'bar' and 'baz', but do not change its value
|
||||
record.write({'active': False, 'foo': "foo3"})
|
||||
self.assertEqual(record.bar, "foo3")
|
||||
self.assertEqual(record.baz, "baz2")
|
||||
|
||||
# recompute 'bar' but not 'baz'
|
||||
record.write({'active': False, 'foo': "foo4", 'bar': "bar4", 'baz': "baz4"})
|
||||
self.assertEqual(record.bar, "foo4")
|
||||
self.assertEqual(record.baz, "baz4")
|
||||
|
||||
def test_set(self):
|
||||
model = self.env['test_new_api.compute.onchange']
|
||||
record = model.create({'active': True, 'foo': "foo"})
|
||||
self.assertEqual(record.bar, "foo")
|
||||
self.assertEqual(record.baz, "foo")
|
||||
|
||||
# recompute 'bar' and 'baz'
|
||||
record.foo = "foo1"
|
||||
self.assertEqual(record.bar, "foo1")
|
||||
self.assertEqual(record.baz, "foo1")
|
||||
|
||||
# do not recompute 'baz'
|
||||
record.baz = "baz2"
|
||||
self.assertEqual(record.bar, "foo1")
|
||||
self.assertEqual(record.baz, "baz2")
|
||||
|
||||
# recompute 'baz', but do not change its value
|
||||
record.active = False
|
||||
self.assertEqual(record.bar, "foo1")
|
||||
self.assertEqual(record.baz, "baz2")
|
||||
|
||||
# recompute 'baz', but do not change its value
|
||||
record.foo = "foo3"
|
||||
self.assertEqual(record.bar, "foo3")
|
||||
self.assertEqual(record.baz, "baz2")
|
||||
|
||||
# do not recompute 'baz'
|
||||
record.baz = "baz4"
|
||||
self.assertEqual(record.bar, "foo3")
|
||||
self.assertEqual(record.baz, "baz4")
|
||||
|
||||
def test_set_new(self):
|
||||
model = self.env['test_new_api.compute.onchange']
|
||||
record = model.new({'active': True, 'foo': "foo"})
|
||||
self.assertEqual(record.bar, "foo")
|
||||
self.assertEqual(record.baz, "foo")
|
||||
|
||||
# recompute 'bar' and 'baz'
|
||||
record.foo = "foo1"
|
||||
self.assertEqual(record.bar, "foo1")
|
||||
self.assertEqual(record.baz, "foo1")
|
||||
|
||||
# do not recompute 'baz'
|
||||
record.baz = "baz2"
|
||||
self.assertEqual(record.bar, "foo1")
|
||||
self.assertEqual(record.baz, "baz2")
|
||||
|
||||
# recompute 'baz', but do not change its value
|
||||
record.active = False
|
||||
self.assertEqual(record.bar, "foo1")
|
||||
self.assertEqual(record.baz, "baz2")
|
||||
|
||||
# recompute 'baz', but do not change its value
|
||||
record.foo = "foo3"
|
||||
self.assertEqual(record.bar, "foo3")
|
||||
self.assertEqual(record.baz, "baz2")
|
||||
|
||||
# do not recompute 'baz'
|
||||
record.baz = "baz4"
|
||||
self.assertEqual(record.bar, "foo3")
|
||||
self.assertEqual(record.baz, "baz4")
|
||||
|
||||
def test_onchange(self):
|
||||
form = common.Form(self.env['test_new_api.compute.onchange'])
|
||||
form.active = True
|
||||
form.foo = "foo1"
|
||||
self.assertEqual(form.bar, "foo1")
|
||||
self.assertEqual(form.baz, "foo1")
|
||||
form.baz = "baz2"
|
||||
self.assertEqual(form.bar, "foo1")
|
||||
self.assertEqual(form.baz, "baz2")
|
||||
form.active = False
|
||||
self.assertEqual(form.bar, "foo1")
|
||||
self.assertEqual(form.baz, "baz2")
|
||||
form.foo = "foo3"
|
||||
self.assertEqual(form.bar, "foo3")
|
||||
self.assertEqual(form.baz, "baz2")
|
||||
form.active = True
|
||||
self.assertEqual(form.bar, "foo3")
|
||||
self.assertEqual(form.baz, "foo3")
|
||||
|
||||
record = form.save()
|
||||
self.assertEqual(record.bar, "foo3")
|
||||
self.assertEqual(record.baz, "foo3")
|
||||
|
||||
form = common.Form(record)
|
||||
self.assertEqual(form.bar, "foo3")
|
||||
self.assertEqual(form.baz, "foo3")
|
||||
form.foo = "foo4"
|
||||
self.assertEqual(form.bar, "foo4")
|
||||
self.assertEqual(form.baz, "foo4")
|
||||
form.baz = "baz5"
|
||||
self.assertEqual(form.bar, "foo4")
|
||||
self.assertEqual(form.baz, "baz5")
|
||||
form.active = False
|
||||
self.assertEqual(form.bar, "foo4")
|
||||
self.assertEqual(form.baz, "baz5")
|
||||
form.foo = "foo6"
|
||||
self.assertEqual(form.bar, "foo6")
|
||||
self.assertEqual(form.baz, "baz5")
|
||||
|
||||
+5
-9
@@ -3315,7 +3315,8 @@ Fields:
|
||||
records_to_inverse[field] = self.filtered('id')
|
||||
if field.relational or self._field_inverses[field]:
|
||||
relational_names.append(fname)
|
||||
protected.update(self._field_computed.get(field, [field]))
|
||||
if field.compute and not field.readonly:
|
||||
protected.update(self._field_computed.get(field, [field]))
|
||||
|
||||
# protect fields being written against recomputation
|
||||
with env.protecting(protected, self):
|
||||
@@ -3516,11 +3517,8 @@ Fields:
|
||||
elif field.inverse:
|
||||
inversed[key] = val
|
||||
inversed_fields.add(field)
|
||||
# ignore the protection of compute fields which do not have an
|
||||
# inverse, otherwise their computation are not correctly
|
||||
# performed, neither the fields which are computed in the same
|
||||
# compute method (`test_validation_error`)
|
||||
if not field.compute or field.inverse:
|
||||
# protect non-readonly computed fields against (re)computation
|
||||
if field.compute and not field.readonly:
|
||||
protected.update(self._field_computed.get(field, [field]))
|
||||
|
||||
data_list.append(data)
|
||||
@@ -5452,9 +5450,7 @@ Fields:
|
||||
# Dont force the recomputation of compute fields which are
|
||||
# not stored as this is not really necessary.
|
||||
if field.compute and field.store:
|
||||
records_to_invalidate = records.filtered(lambda r: not r.id)
|
||||
self.env.add_to_compute(field, records - records_to_invalidate)
|
||||
self.env.cache.invalidate([(field, records_to_invalidate._ids)])
|
||||
self.env.add_to_compute(field, records)
|
||||
else:
|
||||
self.env.cache.invalidate([(field, records._ids)])
|
||||
# recursively trigger recomputation of field's dependents
|
||||
|
||||
Reference in New Issue
Block a user