[FIX] models: do not prefetch fields to recompute, and recompute once only

The method _prefetch_field() was accidentally prefetching fields to recompute;
which was skipping the actual recomputation, since a value was put in cache.
But sometimes the field's value was fixed by an extra recomputation of the
field.  Here we remove the extra recomputation and fix the cache corruption.
This commit is contained in:
Raphael Collet 2014-10-13 12:38:59 +02:00
parent cfa04b1d3d
commit 044ed06fec
2 changed files with 22 additions and 21 deletions

View File

@ -837,11 +837,10 @@ class Environment(object):
def remove_todo(self, field, records):
""" Mark `field` as recomputed on `records`. """
recs_list = self.all.todo.get(field, [])
if records in recs_list:
recs_list.remove(records)
if not recs_list:
del self.all.todo[field]
recs_list = [recs - records for recs in self.all.todo.pop(field, [])]
recs_list = filter(None, recs_list)
if recs_list:
self.all.todo[field] = recs_list
def has_todo(self):
""" Return whether some fields must be recomputed. """

View File

@ -3127,25 +3127,27 @@ class BaseModel(object):
if len(records) > PREFETCH_MAX:
records = records[:PREFETCH_MAX] | self
# by default, simply fetch field
fnames = {field.name}
if self.env.in_draft:
# we may be doing an onchange, do not prefetch other fields
pass
elif self.env.field_todo(field):
# field must be recomputed, do not prefetch records to recompute
records -= self.env.field_todo(field)
elif not self._context.get('prefetch_fields', True):
# do not prefetch other fields
pass
elif self._columns[field.name]._prefetch:
# here we can optimize: prefetch all classic and many2one fields
fnames = set(fname
# determine which fields can be prefetched
if not self.env.in_draft and \
self._context.get('prefetch_fields', True) and \
self._columns[field.name]._prefetch:
# prefetch all classic and many2one fields that the user can access
fnames = {fname
for fname, fcolumn in self._columns.iteritems()
if fcolumn._prefetch
if not fcolumn.groups or self.user_has_groups(fcolumn.groups)
)
}
else:
fnames = {field.name}
# important: never prefetch fields to recompute!
get_recs_todo = self.env.field_todo
for fname in list(fnames):
if get_recs_todo(self._fields[fname]):
if fname == field.name:
records -= get_recs_todo(field)
else:
fnames.discard(fname)
# fetch records with read()
assert self in records and field.name in fnames