Skip to content

Commit

Permalink
[REF] core: simplify BaseModel._flush()
Browse files Browse the repository at this point in the history
_flush() has been simplified because some parts became unnecessary
with the new flush mechanism, which is much more accurate.
  • Loading branch information
ryv-odoo committed Jan 15, 2024
1 parent 6218151 commit ddfc2aa
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 61 deletions.
6 changes: 2 additions & 4 deletions odoo/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1020,8 +1020,7 @@ def set(self, record, field, value, dirty=False, check_dirty=True):
if record.pool.field_depends_context[field]:
# put the values under conventional context key values {'context_key': None},
# in order to ease the retrieval of those values to flush them
context_none = dict.fromkeys(record.pool.field_depends_context[field])
record = record.with_env(record.env(context=context_none))
record = record.with_env(record.env(context={}))
field_cache = self._set_field_cache(record, field)
field_cache[record._ids[0]] = value
elif record.id in self._dirty.get(field, ()):
Expand Down Expand Up @@ -1068,8 +1067,7 @@ def update_raw(self, records, field, values, dirty=False, check_dirty=True):
if records.pool.field_depends_context[field]:
# put the values under conventional context key values {'context_key': None},
# in order to ease the retrieval of those values to flush them
context_none = dict.fromkeys(records.pool.field_depends_context[field])
records = records.with_env(records.env(context=context_none))
records = records.with_env(records.env(context={}))
field_cache = self._set_field_cache(records, field)
field_cache.update(zip(records._ids, values))
else:
Expand Down
88 changes: 31 additions & 57 deletions odoo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6405,69 +6405,43 @@ def flush_recordset(self, fnames=None):
self._flush(fnames)

def _flush(self, fnames=None):
def process(model, id_vals):
# group record ids by vals, to update in batch when possible
updates = defaultdict(list)
for id_, vals in id_vals.items():
updates[frozendict(vals)].append(id_)

for vals, ids in updates.items():
model.browse(ids)._write(vals)

# DLE P76: test_onchange_one2many_with_domain_on_related_field
# ```
# email.important = True
# self.assertIn(email, discussion.important_emails)
# ```
# When a search on a field coming from a related occurs (the domain
# on discussion.important_emails field), make sure the related field
# is flushed
if fnames is None:
fields = self._fields.values()
else:
fields = [self._fields[fname] for fname in fnames]

model_fields = defaultdict(list)
for field in fields:
model_fields[field.model_name].append(field)
if field.related_field:
model_fields[field.related_field.model_name].append(field.related_field)

for model_name, fields_ in model_fields.items():
dirty_fields = self.env.cache.get_dirty_fields()
if any(field in dirty_fields for field in fields_):
# if any field is context-dependent, the values to flush should
# be found with a context where the context keys are all None
context_none = dict.fromkeys(
key
for field in fields_
for key in self.pool.field_depends_context[field]
)
model = self.env(context=context_none)[model_name]
id_vals = defaultdict(dict)
for field in model._fields.values():
ids = self.env.cache.clear_dirty_field(field)
if not ids:
continue
records = model.browse(ids)
values = list(self.env.cache.get_values(records, field))
assert len(values) == len(records), \
f"Could not find all values of {field} to flush them\n" \
f" Context: {self.env.context}\n" \
f" Cache: {self.env.cache!r}"
for record, value in zip(records, values):
if not field.translate:
value = field.convert_to_write(value, record)
value = field.convert_to_column(value, record)
else:
value = field._convert_from_cache_to_column(value)
id_vals[record.id][field.name] = value
process(model, id_vals)
dirty_fields = self.env.cache.get_dirty_fields()
if not any(field in dirty_fields for field in fields):
return

# flush the inverse of one2many fields, too
for field in fields:
if field.type == 'one2many' and field.inverse_name:
self.env[field.comodel_name].flush_model([field.inverse_name])
# if any field is context-dependent, the values to flush should
# be found with a context where the context keys are all None
model = self.with_context(context={})
id_vals = defaultdict(dict)
for field in self._fields.values():
ids = self.env.cache.clear_dirty_field(field)
if not ids:
continue
records = model.browse(ids)
values = list(self.env.cache.get_values(records, field))
assert len(values) == len(records), \
f"Could not find all values of {field} to flush them\n" \
f" Cache: {self.env.cache!r}"
for record, value in zip(records, values):
if not field.translate:
value = field.convert_to_write(value, record)
value = field.convert_to_column(value, record)
else:
value = field._convert_from_cache_to_column(value)
id_vals[record.id][field.name] = value

# group record ids by vals, to update in batch when possible
updates = defaultdict(list)
for id_, vals in id_vals.items():
updates[frozendict(vals)].append(id_)

for vals, ids in updates.items():
model.browse(ids)._write(vals)

#
# New records - represent records that do not exist in the database yet;
Expand Down

0 comments on commit ddfc2aa

Please sign in to comment.