diff --git a/odoo/api.py b/odoo/api.py index 68b92943640..cf56718b032 100644 --- a/odoo/api.py +++ b/odoo/api.py @@ -452,6 +452,7 @@ class Environment(Mapping): self.cr, self.uid, self.context, self.su = self.args = args self.registry = Registry(cr.dbname) self.cache = envs.cache + self._cache_key = {} # memo {field: cache_key} self._protected = envs.protected # proxy to shared data structure self.all = envs envs.add(self) @@ -709,6 +710,36 @@ class Environment(Mapping): """ Delay recomputations (deprecated: this is not the default behavior). """ yield + def cache_key(self, field): + """ Return the cache key corresponding to ``field.depends_context``. """ + try: + return self._cache_key[field] + + except KeyError: + def get(key, get_context=self.context.get): + if key == 'company': + return self.company.id + elif key == 'uid': + return (self.uid, self.su) + elif key == 'active_test': + return get_context('active_test', field.context.get('active_test', True)) + else: + val = get_context(key) + try: + hash(val) + except TypeError: + raise TypeError( + "Can only create cache keys from hashable values, " + "got non-hashable value {!r} at context key {!r} " + "(dependency of field {})".format(val, key, field) + ) from None # we don't need to chain the exception created 2 lines above + else: + return val + + result = tuple(get(key) for key in field.depends_context) + self._cache_key[field] = result + return result + class Environments(object): """ A common object for all environments in a request. """ @@ -742,7 +773,7 @@ class Cache(object): def contains(self, record, field): """ Return whether ``record`` has a value for ``field``. """ if field.depends_context: - key = field.cache_key(record.env) + key = record.env.cache_key(field) return key in self._data.get(field, {}).get(record.id, {}) return record.id in self._data.get(field, ()) @@ -751,7 +782,7 @@ class Cache(object): try: value = self._data[field][record._ids[0]] if field.depends_context: - value = value[field.cache_key(record.env)] + value = value[record.env.cache_key(field)] return value except KeyError: if default is NOTHING: @@ -761,7 +792,7 @@ class Cache(object): def set(self, record, field, value): """ Set the value of ``field`` for ``record``. """ if field.depends_context: - key = field.cache_key(record.env) + key = record.env.cache_key(field) self._data[field].setdefault(record._ids[0], {})[key] = value else: self._data[field][record._ids[0]] = value @@ -769,7 +800,7 @@ class Cache(object): def update(self, records, field, values): """ Set the values of ``field`` for several ``records``. """ if field.depends_context: - key = field.cache_key(records.env) + key = records.env.cache_key(field) field_cache = self._data[field] for record_id, value in zip(records._ids, values): field_cache.setdefault(record_id, {})[key] = value @@ -786,7 +817,7 @@ class Cache(object): def get_values(self, records, field): """ Return the cached values of ``field`` for ``records``. """ field_cache = self._data[field] - key = field.cache_key(records.env) if field.depends_context else None + key = records.env.cache_key(field) if field.depends_context else None for record_id in records._ids: try: if key is not None: @@ -799,7 +830,7 @@ class Cache(object): def get_records_different_from(self, records, field, value): """ Return the subset of ``records`` that has not ``value`` for ``field``. """ field_cache = self._data[field] - key = field.cache_key(records.env) if field.depends_context else None + key = records.env.cache_key(field) if field.depends_context else None ids = [] for record_id in records._ids: try: @@ -822,7 +853,7 @@ class Cache(object): values = self._data.get(field, {}) if record.id not in values: continue - if field.depends_context and field.cache_key(record.env) not in values[record.id]: + if field.depends_context and record.env.cache_key(field) not in values[record.id]: continue yield field diff --git a/odoo/fields.py b/odoo/fields.py index 449544e2250..3982f9c00da 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -632,34 +632,6 @@ class Field(MetaField('DummyField', (object,), {})): Property = records.env['ir.property'] return Property.search_multi(self.name, self.model_name, operator, value) - # - # Cache key for context-dependent fields - # - - def cache_key(self, env): - """ Return the cache key corresponding to ``self.depends_context``. """ - - def get(key, get_context=env.context.get): - if key == 'company': - return env.company.id - elif key == 'uid': - return (env.uid, env.su) - elif key == 'active_test': - return get_context('active_test', self.context.get('active_test', True)) - else: - v = get_context(key) - try: hash(v) - except TypeError: - raise TypeError( - "Can only create cache keys from hashable values, " - "got non-hashable value {!r} at context key {!r} " - "(dependency of field {})".format(v, key, self) - ) from None # we don't need to chain the exception created 2 lines above - else: - return v - - return tuple(get(key) for key in self.depends_context) - # # Setup of field triggers #