diff --git a/openerp/addons/test_new_api/tests/test_onchange.py b/openerp/addons/test_new_api/tests/test_onchange.py index da28bdf0c1b..e9b7e1f83aa 100644 --- a/openerp/addons/test_new_api/tests/test_onchange.py +++ b/openerp/addons/test_new_api/tests/test_onchange.py @@ -146,8 +146,7 @@ class TestOnChange(common.TransactionCase): }), (1, message.id, { 'name': "[%s] %s" % ("Foo", USER.name), - 'body': BODY, - 'author': USER.id, + # Note: size is computed because it was not provided beforehand 'size': len(BODY), }), ]) diff --git a/openerp/api.py b/openerp/api.py index 94ed98c1265..8be6c268ea9 100644 --- a/openerp/api.py +++ b/openerp/api.py @@ -2,7 +2,7 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2013 OpenERP (). +# Copyright (C) 2013-2014 OpenERP (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -717,7 +717,7 @@ class Environment(object): self.cache = defaultdict(dict) # {field: {id: value, ...}, ...} self.prefetch = defaultdict(set) # {model_name: set(id), ...} self.computed = defaultdict(set) # {field: set(id), ...} - self.dirty = set() # set(record) + self.dirty = defaultdict(set) # {record: set(field_name), ...} self.all = envs envs.add(self) return self diff --git a/openerp/fields.py b/openerp/fields.py index 27c0df09a4b..0192fbac6c3 100644 --- a/openerp/fields.py +++ b/openerp/fields.py @@ -791,7 +791,7 @@ class Field(object): if env.in_onchange: for invf in self.inverse_fields: invf._update(value, record) - record._dirty = True + record._set_dirty(self.name) # determine more dependent fields, and invalidate them if self.relational: @@ -1577,13 +1577,14 @@ class _RelationalMulti(_Relational): # add new and existing records for record in value: - if not record.id or record._dirty: - values = dict((k, v) for k, v in record._cache.iteritems() if k in fnames) + if not record.id: + values = {k: v for k, v in record._cache.iteritems() if k in fnames} values = record._convert_to_write(values) - if not record.id: - result.append((0, 0, values)) - else: - result.append((1, record.id, values)) + result.append((0, 0, values)) + elif record._is_dirty(): + values = {k: record._cache[k] for k in record._get_dirty() if k in fnames} + values = record._convert_to_write(values) + result.append((1, record.id, values)) else: add_existing(record.id) diff --git a/openerp/models.py b/openerp/models.py index d5fde6c9fe5..33327ef7279 100644 --- a/openerp/models.py +++ b/openerp/models.py @@ -5343,22 +5343,24 @@ class BaseModel(object): return record # - # Dirty flag, to mark records modified (in draft mode) + # Dirty flags, to mark record fields modified (in draft mode) # - @property - def _dirty(self): + def _is_dirty(self): """ Return whether any record in `self` is dirty. """ dirty = self.env.dirty return any(record in dirty for record in self) - @_dirty.setter - def _dirty(self, value): - """ Mark the records in `self` as dirty. """ - if value: - map(self.env.dirty.add, self) - else: - map(self.env.dirty.discard, self) + def _get_dirty(self): + """ Return the list of field names for which `self` is dirty. """ + dirty = self.env.dirty + return list(dirty.get(self, ())) + + def _set_dirty(self, field_name): + """ Mark the records in `self` as dirty for the given `field_name`. """ + dirty = self.env.dirty + for record in self: + dirty[record].add(field_name) # # "Dunder" methods @@ -5760,7 +5762,7 @@ class BaseModel(object): field = self._fields[name] newval = record[name] if field.type in ('one2many', 'many2many'): - if newval != oldval or newval._dirty: + if newval != oldval or newval._is_dirty(): # put new value in result result['value'][name] = field.convert_to_write( newval, record._origin, subfields.get(name),