[IMP] core: compute field_computed lazily
This is a simple refactoring. X-original-commit: 634775bff6d9eba9d4548cc801071a942895a719
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+4
-17
@@ -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)])
|
||||
|
||||
@@ -266,6 +266,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
|
||||
|
||||
Reference in New Issue
Block a user