[IMP] models: in onchange, keep track of virtual ids of new records
The x2many "create" command is now like: `(0, ref, vals)`, where `ref` is an arbitrary reference that may be used to identify a new line in the relation. The reference is returned in a similar command by the method `onchange`. `onchange` now supports self-modifying x2many fields.
This commit is contained in:
committed by
Christophe Matthieu
parent
7e3f8f2140
commit
6cf98c4c87
@@ -157,6 +157,51 @@ class TestOnChange(common.TransactionCase):
|
||||
}),
|
||||
])
|
||||
|
||||
def test_onchange_one2many_reference(self):
|
||||
""" test the effect of onchange() on one2many fields with line references """
|
||||
BODY = "What a beautiful day!"
|
||||
USER = self.env.user
|
||||
REFERENCE = "virtualid42"
|
||||
|
||||
field_onchange = self.Discussion._onchange_spec()
|
||||
self.assertEqual(field_onchange.get('name'), '1')
|
||||
self.assertEqual(field_onchange.get('messages'), '1')
|
||||
self.assertItemsEqual(
|
||||
strip_prefix('messages.', field_onchange),
|
||||
['author', 'body', 'name', 'size', 'important'],
|
||||
)
|
||||
|
||||
# modify discussion name, and check that the reference of the new line
|
||||
# is returned
|
||||
values = {
|
||||
'name': "Foo",
|
||||
'categories': [],
|
||||
'moderator': False,
|
||||
'participants': [],
|
||||
'messages': [
|
||||
(0, REFERENCE, {
|
||||
'name': "[%s] %s" % ('', USER.name),
|
||||
'body': BODY,
|
||||
'author': USER.id,
|
||||
'size': len(BODY),
|
||||
'important': False,
|
||||
}),
|
||||
],
|
||||
}
|
||||
self.env.invalidate_all()
|
||||
result = self.Discussion.onchange(values, 'name', field_onchange)
|
||||
self.assertIn('messages', result['value'])
|
||||
self.assertItemsEqual(result['value']['messages'], [
|
||||
(5,),
|
||||
(0, REFERENCE, {
|
||||
'name': "[%s] %s" % ("Foo", USER.name),
|
||||
'body': BODY,
|
||||
'author': USER.name_get()[0],
|
||||
'size': len(BODY),
|
||||
'important': False,
|
||||
}),
|
||||
])
|
||||
|
||||
def test_onchange_one2many_multi(self):
|
||||
""" test the effect of multiple onchange methods on one2many fields """
|
||||
partner = self.env.ref('base.res_partner_1')
|
||||
|
||||
+2
-2
@@ -2028,7 +2028,7 @@ class _RelationalMulti(_Relational):
|
||||
for command in value:
|
||||
if isinstance(command, (tuple, list)):
|
||||
if command[0] == 0:
|
||||
ids.add(comodel.new(command[2]).id)
|
||||
ids.add(comodel.new(command[2], command[1]).id)
|
||||
elif command[0] == 1:
|
||||
comodel.browse(command[1]).update(command[2])
|
||||
ids.add(command[1])
|
||||
@@ -2085,7 +2085,7 @@ class _RelationalMulti(_Relational):
|
||||
for record in value:
|
||||
vals = {name: convert(record[name], record) for name, convert in converters}
|
||||
if not record.id:
|
||||
result.append((0, 0, vals))
|
||||
result.append((0, record.id.ref or 0, vals))
|
||||
elif vals:
|
||||
result.append((1, record.id, vals))
|
||||
else:
|
||||
|
||||
+12
-9
@@ -168,7 +168,12 @@ class MetaModel(api.Meta):
|
||||
|
||||
|
||||
class NewId(object):
|
||||
""" Pseudo-ids for new records. """
|
||||
""" Pseudo-ids for new records, encapsulating an optional reference. """
|
||||
__slots__ = ['ref']
|
||||
|
||||
def __init__(self, ref=None):
|
||||
self.ref = ref
|
||||
|
||||
def __bool__(self):
|
||||
return False
|
||||
__nonzero__ = __bool__
|
||||
@@ -4445,14 +4450,17 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
#
|
||||
|
||||
@api.model
|
||||
def new(self, values={}):
|
||||
def new(self, values={}, ref=None):
|
||||
""" new([values]) -> record
|
||||
|
||||
Return a new record instance attached to the current environment and
|
||||
initialized with the provided ``value``. The record is *not* created
|
||||
in database, it only exists in memory.
|
||||
|
||||
One can pass a reference value to identify the record among other new
|
||||
records. The reference is encapsulated in the ``id`` of the record.
|
||||
"""
|
||||
record = self.browse([NewId()])
|
||||
record = self.browse([NewId(ref)])
|
||||
record._cache.update(record._convert_to_cache(values, update=True))
|
||||
|
||||
if record.env.in_onchange:
|
||||
@@ -4978,12 +4986,6 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
todo.append(name)
|
||||
dirty.add(name)
|
||||
|
||||
# At the moment, the client does not support updates on a *2many field
|
||||
# while this one is modified by the user.
|
||||
if isinstance(field_name, pycompat.string_types) and \
|
||||
self._fields[field_name].type in ('one2many', 'many2many'):
|
||||
dirty.discard(field_name)
|
||||
|
||||
# collect values from dirty fields
|
||||
result['value'] = {
|
||||
name: self._fields[name].convert_to_onchange(record[name], record, subfields[name])
|
||||
@@ -4991,6 +4993,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
collections.Set.register(BaseModel)
|
||||
# not exactly true as BaseModel doesn't have __reversed__, index or count
|
||||
collections.Sequence.register(BaseModel)
|
||||
|
||||
Reference in New Issue
Block a user