[FIX] models, fields, api: do not mix the cache format with the record format
This commit is contained in:
+6
-2
@@ -1036,6 +1036,8 @@ class Environment(object):
|
||||
|
||||
def check_cache(self):
|
||||
""" Check the cache consistency. """
|
||||
from openerp.fields import SpecialValue
|
||||
|
||||
# make a full copy of the cache, and invalidate it
|
||||
cache_dump = dict(
|
||||
(field, dict(field_cache))
|
||||
@@ -1051,9 +1053,11 @@ class Environment(object):
|
||||
for record in records:
|
||||
try:
|
||||
cached = field_dump[record.id]
|
||||
cached = cached.get() if isinstance(cached, SpecialValue) else cached
|
||||
value = field.convert_to_record(cached, record)
|
||||
fetched = record[field.name]
|
||||
if fetched != cached:
|
||||
info = {'cached': cached, 'fetched': fetched}
|
||||
if fetched != value:
|
||||
info = {'cached': value, 'fetched': fetched}
|
||||
invalids.append((field, record, info))
|
||||
except (AccessError, MissingError):
|
||||
pass
|
||||
|
||||
+19
-16
@@ -52,11 +52,12 @@ def copy_cache(records, env):
|
||||
if record not in done:
|
||||
done.add(record)
|
||||
target = record.with_env(env)
|
||||
for name, value in record._cache.iteritems():
|
||||
for name in record._cache:
|
||||
field = record._fields[name]
|
||||
value = record[name]
|
||||
if isinstance(value, BaseModel):
|
||||
todo.update(value)
|
||||
value = value.with_env(env)
|
||||
target._cache[name] = value
|
||||
target._cache[name] = field.convert_to_cache(value, target, validate=False)
|
||||
|
||||
|
||||
def resolve_mro(model, name, predicate):
|
||||
@@ -88,12 +89,9 @@ def default_new_to_old(field, value):
|
||||
def default_old_to_new(field, value):
|
||||
""" Convert the old-API default ``value`` to the new API. """
|
||||
if callable(value):
|
||||
return lambda model: field.convert_to_cache(
|
||||
value(model._model, model._cr, model._uid, model._context),
|
||||
model, validate=False,
|
||||
)
|
||||
return lambda model: value(model._model, model._cr, model._uid, model._context)
|
||||
else:
|
||||
return lambda model: field.convert_to_cache(value, model, validate=False)
|
||||
return lambda model: value
|
||||
|
||||
def default_old_to_old(field, value):
|
||||
""" Convert the old-API default ``value`` to the old API. """
|
||||
@@ -860,7 +858,7 @@ class Field(object):
|
||||
record._cache[self] = value
|
||||
if env.in_onchange:
|
||||
for invf in record._field_inverses[self]:
|
||||
invf._update(value, record)
|
||||
invf._update(record[self.name], record)
|
||||
record._set_dirty(self.name)
|
||||
|
||||
# determine more dependent fields, and invalidate them
|
||||
@@ -1685,8 +1683,11 @@ class Many2one(_Relational):
|
||||
_column_auto_join = property(attrgetter('auto_join'))
|
||||
|
||||
def _update(self, records, value):
|
||||
""" Update the cached value of ``self`` for ``records`` with ``value``. """
|
||||
records._cache[self] = value
|
||||
""" Update the cached value of ``self`` for ``records`` with ``value``.
|
||||
This is used to reflect the assignment ``value[name] = records``, where
|
||||
``name`` is the inverse field of ``self``.
|
||||
"""
|
||||
records._cache[self] = self.convert_to_cache(value, records, validate=False)
|
||||
|
||||
def convert_to_cache(self, value, record, validate=True):
|
||||
if isinstance(value, (NoneType, int, long)):
|
||||
@@ -1741,8 +1742,9 @@ class UnionUpdate(SpecialValue):
|
||||
# in order to read the current field's value, remove self from cache
|
||||
del record._cache[field]
|
||||
# read the current field's value, and update it in cache only
|
||||
record._cache[field] = new_value = record[field.name] | value
|
||||
return new_value
|
||||
value = field.convert_to_cache(record[field.name] | value, record, validate=False)
|
||||
record._cache[field] = value
|
||||
return value
|
||||
|
||||
|
||||
class _RelationalMulti(_Relational):
|
||||
@@ -1752,9 +1754,10 @@ class _RelationalMulti(_Relational):
|
||||
""" Update the cached value of ``self`` for ``records`` with ``value``. """
|
||||
for record in records:
|
||||
if self in record._cache:
|
||||
record._cache[self] = record[self.name] | value
|
||||
value = self.convert_to_cache(record[self.name] | value, record, validate=False)
|
||||
else:
|
||||
record._cache[self] = UnionUpdate(self, record, value)
|
||||
value = UnionUpdate(self, record, value)
|
||||
record._cache[self] = value
|
||||
|
||||
def convert_to_cache(self, value, record, validate=True):
|
||||
if isinstance(value, BaseModel):
|
||||
@@ -1805,7 +1808,7 @@ class _RelationalMulti(_Relational):
|
||||
result = [(5,)]
|
||||
for record in value:
|
||||
if not record.id:
|
||||
values = dict(record._cache)
|
||||
values = {name: record[name] for name in record._cache}
|
||||
values = record._convert_to_write(values)
|
||||
result.append((0, 0, values))
|
||||
elif record._is_dirty():
|
||||
|
||||
+11
-2
@@ -5665,6 +5665,15 @@ class BaseModel(object):
|
||||
if name in fields
|
||||
}
|
||||
|
||||
def _convert_to_record(self, values):
|
||||
""" Convert the ``values`` dictionary from the cache format to the
|
||||
record format.
|
||||
"""
|
||||
return {
|
||||
name: self._fields[name].convert_to_record(value, self)
|
||||
for name, value in values.iteritems()
|
||||
}
|
||||
|
||||
def _convert_to_write(self, values):
|
||||
""" Convert the ``values`` dictionary into the format of :meth:`write`. """
|
||||
fields = self._fields
|
||||
@@ -6099,7 +6108,7 @@ class BaseModel(object):
|
||||
return
|
||||
if res.get('value'):
|
||||
res['value'].pop('id', None)
|
||||
self.update(self._convert_to_cache(res['value'], validate=False))
|
||||
self.update(res['value'])
|
||||
if res.get('domain'):
|
||||
result.setdefault('domain', {}).update(res['domain'])
|
||||
if res.get('warning'):
|
||||
@@ -6188,7 +6197,7 @@ class BaseModel(object):
|
||||
# create a new record with values, and attach ``self`` to it
|
||||
with env.do_in_onchange():
|
||||
record = self.new(values)
|
||||
values = dict(record._cache)
|
||||
values = {name: record[name] for name in record._cache}
|
||||
# attach ``self`` with a different context (for cache consistency)
|
||||
record._origin = self.with_context(__onchange=True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user