From cb1cfadda23cc1e1d73f4ef854ec82c294febd09 Mon Sep 17 00:00:00 2001 From: Raphael Collet <rco@odoo.com> Date: Mon, 9 Oct 2017 11:53:18 +0200 Subject: [PATCH] [FIX] fields: performance issue in `copy_cache` (#19963) That function is called when computing related fields in onchange mode. The new implementation makes a direct access to the cache's implementation. opw-772303 --- odoo/fields.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/odoo/fields.py b/odoo/fields.py index 745e5effb62e..60aefa9bc25d 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -53,18 +53,23 @@ def _check_value(value): def copy_cache(records, env): """ Recursively copy the cache of ``records`` to the environment ``env``. """ - todo, done = set(records), set() + src = records.env + todo = defaultdict(set) # {model_name: ids} + done = defaultdict(set) # {model_name: ids} + todo[records._name].update(records._ids) while todo: - record = todo.pop() - if record not in done: - done.add(record) - target = record.with_env(env) - for name in record._cache: - field = record._fields[name] - value = record[name] - if isinstance(value, BaseModel): - todo.update(value) - target._cache[name] = field.convert_to_cache(value, target, validate=False) + model_name = next(iter(todo)) + record_ids = todo.pop(model_name) - done[model_name] + done[model_name].update(record_ids) + for name, field in src[model_name]._fields.items(): + src_cache = src.cache[field] + dst_cache = env.cache[field] + for record_id in record_ids: + if record_id in src_cache: + # copy the cached value as such + value = dst_cache[record_id] = src_cache[record_id] + if field.relational and isinstance(value, tuple): + todo[field.comodel_name].update(value) def resolve_mro(model, name, predicate): -- GitLab