该操作符是用于多层继承结构的查询,和in不同,

我们有如下表格product.category,parent_id 外键关联到自身的表格,可以设置记录之间的层级关系.

 id | parent_path |       name       |            complete_name             | parent_id |
----+-------------+------------------+--------------------------------------+-----------+
1 | 1/ | All | All | |
2 | 1/2/ | Saleable | All / Saleable | 1 |
3 | 1/3/ | Expenses | All / Expenses | 1 |
4 | 1/4/ | Internal | All / Internal | 1 |
5 | 1/2/5/ | Services | All / Saleable / Services | 2 |
6 | 1/2/5/6/ | Saleable | All / Saleable / Services / Saleable | 5 |
7 | 1/2/7/ | Software | All / Saleable / Software | 2 |
8 | 1/2/8/ | Office Furniture | All / Saleable / Office Furniture | 2 |
9 | 1/9/ | Consumable | All / Consumable | 1 |
(9 行记录)

假如我要查询id=2 的所有子记录(包含子记录的子记录),就可以使用child_of 操作符:

categ = self.env.get('product.category').browse(2)
categ.search([('id', 'child_of', categ.id)]).ids
# [2, 8, 5, 6, 7]

同理,也可以查询某一条记录的所有父记录,

目前还明白算法是怎样实现的,但是算法的代码应该如下:

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_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:
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
else:
parent_name = parent or left_model._parent_name
child_ids = set(ids)
while ids:
ids = left_model.search([(parent_name, 'in', ids)]).ids
child_ids.update(ids)
return [(left, 'in', list(child_ids))]

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_path tree lookup field
(when available), or as an expanded [(left,in,parent_ids)] """
if left_model._parent_store:
parent_ids = [
int(label)
for rec in left_model.browse(ids)
for label in rec.parent_path.split('/')[:-1]
]
if prefix:
return [(left, 'in', parent_ids)]
return [('id', 'in', parent_ids)]
else:
parent_name = parent or left_model._parent_name
parent_ids = set()
for record in left_model.browse(ids):
while record:
parent_ids.add(record.id)
record = record[parent_name]
return [(left, 'in', list(parent_ids))]

懂得,原来世界如此简单!