該操作符是用於多層繼承結構的查詢,和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))]