diff options
| author | Raphael Collet <rco@odoo.com> | 2019-09-23 13:41:18 +0000 |
|---|---|---|
| committer | Raphael Collet <rco@odoo.com> | 2019-09-30 15:42:36 +0000 |
| commit | 4b1cb41cf7a3f936a1e6d00a2bb6a6a29e82d711 (patch) | |
| tree | c222eb33232a664293d7363cd42d50b87b80341f /odoo/fields.py | |
| parent | 333f1087cf50efa4e053e5d9fef0b80e421967f1 (diff) | |
[FIX] models, fields: cache consistency for one2many fields
Issue: after many2one updates, the cache of the corresponding one2many
fields was inconsistent when the latter depends on `active_test`. One
of the values in cache was updated, while the other was left intact.
We simplify the cache by not making the field depend on context: the
cache value contains all the records in the relation (corresponding to
`active_test=False`). The value of the field is automatically filtered
by the `active` field when the value is accessed.
This makes it easier to maintain the cache value, guarantees its
consistency, and avoids queries to read the one2many field with
`active_test=False`, after having set it with `active_test=True`.
Diffstat (limited to 'odoo/fields.py')
| -rw-r--r-- | odoo/fields.py | 37 |
1 files changed, 18 insertions, 19 deletions
diff --git a/odoo/fields.py b/odoo/fields.py index 1bb934cd70c..78ccb5b2857 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -2562,6 +2562,10 @@ class Many2oneReference(Integer): class _RelationalMulti(_Relational): """ Abstract class for relational fields *2many. """ + # Important: the cache contains the ids of all the records in the relation, + # including inactive records. Inactive records are filtered out by + # convert_to_record(), depending on the context. + def _update(self, records, value): """ Update the cached value of ``self`` for ``records`` with ``value``, and return whether everything is in cache. @@ -2575,26 +2579,17 @@ class _RelationalMulti(_Relational): return records = model.browse(records) - cache = records.env.cache result = True - if 'active_test' in (self.depends_context or ()): - updates = [ - (value.sudo().filtered('active'), records.with_context(active_test=True)), - (value, records.with_context(active_test=False)), - ] - else: - updates = [(value, records)] - for value, recs in updates: - if not value: - continue - for record in recs: + if value: + cache = records.env.cache + for record in records: if cache.contains(record, self): val = self.convert_to_cache(record[self.name] | value, record, validate=False) cache.set(record, self, val) else: result = False - recs.modified([self.name]) + records.modified([self.name]) return result @@ -2654,7 +2649,10 @@ class _RelationalMulti(_Relational): def convert_to_record(self, value, record): # use registry to avoid creating a recordset for the model prefetch_ids = IterableGenerator(prefetch_x2many_ids, record, self) - return record.pool[self.comodel_name]._browse(record.env, value, prefetch_ids) + corecords = record.pool[self.comodel_name]._browse(record.env, value, prefetch_ids) + if 'active' in corecords and record.env.context.get('active_test', True): + corecords = corecords.filtered('active').with_prefetch(prefetch_ids) + return corecords def convert_to_read(self, value, record, use_name_get=True): return value.ids @@ -2711,9 +2709,6 @@ class _RelationalMulti(_Relational): for arg in self.domain if isinstance(arg, (tuple, list)) and isinstance(arg[0], str) ) - # make self depend on 'active_test' if there is a field 'active' in the comodel - if 'active' in model.env[self.comodel_name] and 'active_test' not in (self.depends_context or ()): - self.depends_context = (self.depends_context or ()) + ('active_test',) def create(self, record_values): """ Write the value of ``self`` on the given records, which have just @@ -2824,7 +2819,9 @@ class One2many(_RelationalMulti): def read(self, records): # retrieve the lines in the comodel - comodel = records.env[self.comodel_name].with_context(**self.context) + context = {'active_test': False} + context.update(self.context) + comodel = records.env[self.comodel_name].with_context(**context) inverse = self.inverse_name inverse_field = comodel._fields[inverse] get_id = (lambda rec: rec.id) if inverse_field.type == 'many2one' else int @@ -3184,7 +3181,9 @@ class Many2many(_RelationalMulti): reflect(model, '%s_%s_fkey' % (self.relation, self.column2), 'f', None, self._module) def read(self, records): - comodel = records.env[self.comodel_name].with_context(**self.context) + context = {'active_test': False} + context.update(self.context) + comodel = records.env[self.comodel_name].with_context(**context) domain = self.get_domain_list(records) wquery = comodel._where_calc(domain) comodel._apply_ir_rules(wquery, 'read') |
