diff options
| author | Raphael Collet <rco@odoo.com> | 2018-01-25 15:08:16 +0100 |
|---|---|---|
| committer | Raphael Collet <rco@odoo.com> | 2018-02-28 10:33:44 +0100 |
| commit | e724858d508a2a7a938455a49f7dc509f6eac4c6 (patch) | |
| tree | 612611d67a4d44991b3757ad1dcd94d872c7de9b /odoo/osv | |
| parent | 80f1ac3599ee630e7556ff4fcf3eb192931eccd8 (diff) | |
[REF] models: use `parent_path` to implement parent_store
This replaces the former modified preorder tree traversal (MPTT) with the
fields `parent_left`/`parent_right`. Each record is associated to a string
`parent_path`, that represents the path from its root node to itself. The path
is made of the node ids suffixed with a slash:
a node | id | parent_path
/ \ a | 42 | 42/
... b b | 63 | 42/63/
/ \ c | 84 | 42/63/84/
c d d | 85 | 42/63/85/
This field provides an efficient implementation for parent_of/child_of queries:
the nodes in the subtree of record are the ones where `parent_path` starts with
the `parent_path` of record. It is also more efficient to maintain than the
MPTT fields, and less sensitive to concurrent updates, because the value of
`parent_path` does not depend on sibling nodes.
Diffstat (limited to 'odoo/osv')
| -rw-r--r-- | odoo/osv/expression.py | 29 |
1 files changed, 13 insertions, 16 deletions
diff --git a/odoo/osv/expression.py b/odoo/osv/expression.py index d9719740edb..9e2bb7228e2 100644 --- a/odoo/osv/expression.py +++ b/odoo/osv/expression.py @@ -737,18 +737,15 @@ class expression(object): def child_of_domain(left, ids, left_model, parent=None, prefix=''): """ Return a domain implementing the child_of operator for [(left,child_of,ids)], - either as a range using the parent_left/right tree lookup fields + either as a range using the parent_path tree lookup field (when available), or as an expanded [(left,in,child_ids)] """ if not ids: return FALSE_DOMAIN if left_model._parent_store: - # TODO: Improve where joins are implemented for many with '.', replace by: - # doms += ['&',(prefix+'.parent_left','<',rec.parent_right),(prefix+'.parent_left','>=',rec.parent_left)] - doms = [] - for rec in left_model.browse(ids): - if doms: - doms.insert(0, OR_OPERATOR) - doms += [AND_OPERATOR, ('parent_left', '<', rec.parent_right), ('parent_left', '>=', rec.parent_left)] + doms = OR([ + [('parent_path', '=like', rec.parent_path + '%')] + for rec in left_model.browse(ids) + ]) if prefix: return [(left, 'in', left_model.search(doms).ids)] return doms @@ -762,17 +759,17 @@ class expression(object): def parent_of_domain(left, ids, left_model, parent=None, prefix=''): """ Return a domain implementing the parent_of operator for [(left,parent_of,ids)], - either as a range using the parent_left/right tree lookup fields + either as a range using the parent_path tree lookup field (when available), or as an expanded [(left,in,parent_ids)] """ if left_model._parent_store: - doms = [] - for rec in left_model.browse(ids): - if doms: - doms.insert(0, OR_OPERATOR) - doms += [AND_OPERATOR, ('parent_right', '>', rec.parent_left), ('parent_left', '<=', rec.parent_left)] + parent_ids = [ + int(label) + for rec in left_model.browse(ids) + for label in rec.parent_path.split('/')[:-1] + ] if prefix: - return [(left, 'in', left_model.search(doms).ids)] - return doms + return [(left, 'in', parent_ids)] + return [('id', 'in', parent_ids)] else: parent_name = parent or left_model._parent_name parent_ids = set() |
