summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphael Collet <rco@odoo.com>2020-04-02 06:45:54 +0000
committerRaphael Collet <rco@odoo.com>2020-04-03 11:40:28 +0000
commit892e3df7010729da96278becbec29d7fe1f0985d (patch)
tree3b62bc4667b3427aa0ccd7ad50311193843017ed
parent0551e7ad54bea744fc546682a0070327807d5e36 (diff)
[IMP] core: compute field_computed lazily
This is a simple refactoring. X-original-commit: 634775bff6d9eba9d4548cc801071a942895a719
-rw-r--r--addons/base_automation/models/base_automation.py2
-rw-r--r--addons/event/models/event_event.py2
-rw-r--r--addons/mail/models/mail_thread.py2
-rw-r--r--odoo/fields.py4
-rw-r--r--odoo/models.py21
-rw-r--r--odoo/modules/registry.py16
6 files changed, 25 insertions, 22 deletions
diff --git a/addons/base_automation/models/base_automation.py b/addons/base_automation/models/base_automation.py
index 3ac633948c0..5051ed9f60d 100644
--- a/addons/base_automation/models/base_automation.py
+++ b/addons/base_automation/models/base_automation.py
@@ -343,7 +343,7 @@ class BaseAutomation(models.Model):
#
def _compute_field_value(self, field):
# determine fields that may trigger an action
- stored_fields = [f for f in self._field_computed[field] if f.store]
+ stored_fields = [f for f in self.pool.field_computed[field] if f.store]
if not any(stored_fields):
return _compute_field_value.origin(self, field)
# retrieve the action rules to possibly execute
diff --git a/addons/event/models/event_event.py b/addons/event/models/event_event.py
index 00ca45c62a7..de6edbef4fb 100644
--- a/addons/event/models/event_event.py
+++ b/addons/event/models/event_event.py
@@ -342,7 +342,7 @@ class EventEvent(models.Model):
""" Make it separate from ``_compute_from_event_type`` because otherwise
a value given at create (see create override) would protect all other fields
depending on event type id from being computed as compute method will be
- blacklisted during create (see ``_field_computed`` attribute used in create
+ blacklisted during create (see ``registry.field_computed`` attribute used in create
to compute protected field from re-computation) """
for event in self:
if event.event_type_id.seats_max:
diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py
index ff31ce7deb6..8b639ae5207 100644
--- a/addons/mail/models/mail_thread.py
+++ b/addons/mail/models/mail_thread.py
@@ -324,7 +324,7 @@ class MailThread(models.AbstractModel):
def _compute_field_value(self, field):
if not self._context.get('tracking_disable') and not self._context.get('mail_notrack'):
- self._prepare_tracking(f.name for f in self._field_computed[field] if f.store)
+ self._prepare_tracking(f.name for f in self.pool.field_computed[field] if f.store)
return super()._compute_field_value(field)
diff --git a/odoo/fields.py b/odoo/fields.py
index 2f4764f6233..11ba2836853 100644
--- a/odoo/fields.py
+++ b/odoo/fields.py
@@ -1044,7 +1044,7 @@ class Field(MetaField('DummyField', (object,), {})):
if new_ids:
# new records: no business logic
new_records = records.browse(new_ids)
- with records.env.protecting(records._field_computed.get(self, [self]), records):
+ with records.env.protecting(records.pool.field_computed.get(self, [self]), records):
new_records.modified([self.name])
self.write(new_records, value)
if self.relational:
@@ -1071,7 +1071,7 @@ class Field(MetaField('DummyField', (object,), {})):
env = records.env
if self.compute_sudo:
records = records.sudo()
- fields = records._field_computed[self]
+ fields = records.pool.field_computed[self]
# Just in case the compute method does not assign a value, we already
# mark the computation as done. This is also necessary if the compute
diff --git a/odoo/models.py b/odoo/models.py
index 9b8bd13d507..1c0ecbc20ee 100644
--- a/odoo/models.py
+++ b/odoo/models.py
@@ -2707,7 +2707,6 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
self._add_inherited_fields()
# 4. initialize more field metadata
- cls._field_computed = {} # fields computed with the same method
cls._field_inverses = Collector() # inverse fields for related fields
cls._setup_done = True
@@ -2763,18 +2762,6 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
field = cls._fields['display_name']
field.depends = tuple(name for name in field.depends if name != 'x_name')
- # map each field to the fields computed with the same method
- groups = defaultdict(list)
- for field in cls._fields.values():
- if field.compute:
- cls._field_computed[field] = group = groups[field.compute]
- group.append(field)
- for fields in groups.values():
- compute_sudo = fields[0].compute_sudo
- if not all(field.compute_sudo == compute_sudo for field in fields):
- _logger.warning("%s: inconsistent 'compute_sudo' for computed fields: %s",
- self._name, ", ".join(field.name for field in fields))
-
@api.model
def _setup_complete(self):
""" Setup recomputation triggers, and complete the model setup. """
@@ -3546,7 +3533,7 @@ Record ids: %(records)s
# will automatically invalidate the field from the cache,
# forcing its value to be recomputed once dependencies are
# up-to-date.
- protected.update(self._field_computed.get(field, [field]))
+ protected.update(self.pool.field_computed.get(field, [field]))
if fname == 'company_id' or (field.relational and field.check_company):
check_company = True
@@ -3753,7 +3740,7 @@ Record ids: %(records)s
inversed_fields.add(field)
# protect non-readonly computed fields against (re)computation
if field.compute and not field.readonly:
- protected.update(self._field_computed.get(field, [field]))
+ protected.update(self.pool.field_computed.get(field, [field]))
data_list.append(data)
@@ -3955,7 +3942,7 @@ Record ids: %(records)s
if field.store and any(self._ids):
# check constraints of the fields that have been computed
- fnames = [f.name for f in self._field_computed[field]]
+ fnames = [f.name for f in self.pool.field_computed[field]]
self.filtered('id')._validate_fields(fnames)
def _parent_store_create(self):
@@ -5828,7 +5815,7 @@ Record ids: %(records)s
# mark the field as computed on missing records, otherwise
# they remain forever in the todo list, and lead to an
# infinite loop...
- for f in recs._field_computed[field]:
+ for f in recs.pool.field_computed[field]:
self.env.remove_to_compute(f, recs - existing)
else:
self.env.cache.invalidate([(field, recs._ids)])
diff --git a/odoo/modules/registry.py b/odoo/modules/registry.py
index ec07606d6f9..843cc14d97c 100644
--- a/odoo/modules/registry.py
+++ b/odoo/modules/registry.py
@@ -267,6 +267,22 @@ class Registry(Mapping):
self.registry_invalidated = True
@lazy_property
+ def field_computed(self):
+ """ Return a dict mapping each field to the fields computed by the same method. """
+ computed = {}
+ for Model in self.models.values():
+ groups = defaultdict(list)
+ for field in Model._fields.values():
+ if field.compute:
+ computed[field] = group = groups[field.compute]
+ group.append(field)
+ for fields in groups.values():
+ if len({field.compute_sudo for field in fields}) > 1:
+ _logger.warning("%s: inconsistent 'compute_sudo' for computed fields: %s",
+ self._name, ", ".join(field.name for field in fields))
+ return computed
+
+ @lazy_property
def field_triggers(self):
# determine field dependencies
dependencies = {}