diff options
| author | Raphael Collet <rco@odoo.com> | 2019-08-27 09:51:04 +0000 |
|---|---|---|
| committer | Raphael Collet <rco@odoo.com> | 2019-09-09 13:18:48 +0000 |
| commit | cfb08e87b0fa8895ec4406c9b30d2ebdb790e346 (patch) | |
| tree | 4ac1ff2d8a34e3fb215dfb6b562f287fea71bf34 /odoo/fields.py | |
| parent | 3d2df88ffd5cfb9644bc54744a6c9b9a7fcfc264 (diff) | |
[FIX] models: use transitive triggers instead of recursion
On average, this reduces the total time spent in method `modified` by
half (times measured on invoice creation and post).
Diffstat (limited to 'odoo/fields.py')
| -rw-r--r-- | odoo/fields.py | 61 |
1 files changed, 15 insertions, 46 deletions
diff --git a/odoo/fields.py b/odoo/fields.py index d658ad5782c..995a586739f 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -692,64 +692,33 @@ class Field(MetaField('DummyField', (object,), {})): # # Setup of field triggers # - # The triggers of a field F is a tree that contains the fields that depend - # on F, together with the fields to inverse to find out which records to - # recompute. - # - # For instance, assume that G depends on F, H depends on X.F, I depends on - # W.X.F, and J depends on Y.F. The triggers of F will be the tree: - # - # [G] - # X/ \Y - # [H] [J] - # W/ - # [I] - # - # This tree provides perfect support for the trigger mechanism: - # when F is # modified on records, - # - mark G to recompute on records, - # - mark H to recompute on inverse(X, records), - # - mark I to recompute on inverse(W, inverse(X, records)), - # - mark J to recompute on inverse(Y, records). - - def setup_triggers(self, model): - def add_trigger(field, path): - """ add a trigger on field to recompute self """ - field_model = model.env[field.model_name] - # trigger computations depending on one2many fields only at creation - nodes = [field_model._field_triggers_create.setdefault(field, {})] - if (field.type != 'one2many') or not field_model._field_inverses[field]: - nodes.append(field_model._field_triggers.setdefault(field, {})) - for node in nodes: - for f in reversed(path): - node = node.setdefault(f, {}) - n = node.setdefault(None, []) - if self not in n: n.append(self) + def resolve_depends(self, model): + """ Return the dependencies of `self` as a collection of field tuples. """ for dotnames in self.depends: + field_seq = [] field_model = model - path = [] # fields from model to field_model - for fname in dotnames.split('.'): - field = field_model._fields[fname] - + for index, fname in enumerate(dotnames.split('.')): if model._transient and not field_model._transient: # modifying fields on regular models should not trigger # recomputations of fields on transient models break - # Do not make self trigger itself - # e.g. `fields.One2many('stock.move.line', 'move_id', domain=[('product_qty', '=', 0.0)])` - # will have 'move_line_nosuggest_ids.product_qty' as a dependency - if (field is not self) or path: - add_trigger(field, path) - - if (field is self) and path: + field = field_model._fields[fname] + if field is self and index: self.recursive = True - path.append(field) + field_seq.append(field) + + # do not make self trigger itself: for instance, a one2many + # field line_ids with domain [('foo', ...)] will have + # 'line_ids.foo' as a dependency + if not (field is self and not index): + yield tuple(field_seq) + if field.type in ('one2many', 'many2many'): for inv_field in field_model._field_inverses[field]: - add_trigger(inv_field, path) + yield tuple(field_seq) + (inv_field,) field_model = model.env.get(field.comodel_name) |
