建議觀看影片, 會更清楚:smile:
建議在閱讀這篇文章之前, 請先確保了解看過以下的文章 (因為都有連貫的關係)
主要介紹 odoo 中如何實現 階層(hierarchy) 的關係.
之前不管是介紹 Many2one 還是 One2many, 都是對別的 model 產生關聯,
那有沒有和自己產生關聯的呢:smile:
答案是有的哦, 就是 odoo 中的 階層(hierarchy) 的關係:satisfied:
階層(hierarchy) 的關係範例圖如下,
接著來看教學的範例,
class DemoHierarchyTutorial(models.Model):
_name = 'demo.hierarchy'
_description = 'Demo Hierarchy Tutorial'
name = fields.Char(string='name', index=True)
parent_id = fields.Many2one('demo.hierarchy', string='Related Partner', index=True)
parent_name = fields.Char(related='parent_id.name', readonly=True, string='Parent name')
child_ids = fields.One2many('demo.hierarchy', 'parent_id', string='Contacts', domain=[('active', '=', True)])
active = fields.Boolean(default=True)
比較特別的就是 parent_id
和 child_ids
都關聯到同一個 model (也就是自己本身 demo.hierarchy
),
然後一個是 Many2one parent_id
和 One2many child_ids
.
<record id="view_form_demo_hierarchy" model="ir.ui.view">
<field name="name">Demo Hierarchy Form</field>
<field name="model">demo.hierarchy</field>
<field name="arch" type="xml">
<form string="Demo Hierarchy">
<sheet>
<group>
<field name="name"/>
<field name="active"/>
<field name="parent_id"/>
<field name="parent_name"/>
</group>
<notebook>
<page string="Hierarchy">
<field name="child_ids" mode="kanban">
<form string="Contact / Address">
<sheet>
<field name="parent_id" invisible="1"/>
<hr/>
<group>
<field name="name" string="Contact Name"/>
</group>
</sheet>
</form>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
寫法和一般的 Many2one 或 One2many 是一樣的, 然後在 One2many 裡面,
將 parent_id
隱藏起來, 因為不需要.
<field name="parent_id" invisible="1"/>
先來建立一比 demo.hierarchy
(test1), parent_id
先不填
點選 add 再建立一比 demo.hierarchy
(test2)
呈現效果如下, test2 的 parent 就是 test1
點選 add 再建立一比 demo.hierarchy
(test3),
呈現效果如下, test2 和 test1 的 parent 都是 test1
tree 的部份
db 中的狀態
在 odoo 中很常看到 child_of 和 parent_of,
可以參考 Contact res.partner
.
odoo 原始碼中的範例, 路徑 odoo/addons/base/models/res_partner.py
class Partner(models.Model):
_description = 'Contact'
_inherit = ['format.address.mixin']
_name = "res.partner"
_order = "display_name"
......
parent_id = fields.Many2one('res.partner', string='Related Company', index=True)
parent_name = fields.Char(related='parent_id.name', readonly=True, string='Parent name')
child_ids = fields.One2many('res.partner', 'parent_id', string='Contacts', domain=[('active', '=', True)])
ref = fields.Char(string='Internal Reference', index=True)
......
其中 parent_id 是 Many2one 的關係 , 而 child_ids 則是 One2many的關係.
階層關係如下
db 關係如下
階層關係如下
db 關係如下
child_of
>>> self.env['res.partner'].search([('id', 'child_of', 14)]) #(小技巧, 從後面看回來, 14 的孩子)
res.partner(14, 26, 33, 27, 68)
>>> self.env['res.partner'].search([('id', 'child_of', [11])])
res.partner(11, 20, 22, 31, 23)
child_of 也可以一次找多個
>>> self.env['res.partner'].search([('id', 'child_of', [14, 11])])
res.partner(14, 26, 33, 27, 68......)
parent_of
>>> self.env['res.partner'].search([('id', 'parent_of', 68)]) #(小技巧, 從後面看回來, 68 的父親)
res.partner(14, 68, 26)
在 odoo 原始碼中, 可能會看到以下的 code
('company_id','child_of',[user.company_id.id])]
問題點在於為甚麼要別使用 []
我這邊猜測應該是為了要避免 WARNING
>>> self.env['res.partner'].search([('id', 'parent_of', [False])])
res.partner()
>>> self.env['res.partner'].search([('id', 'parent_of', False)]) # 會有 WARNING
2020-07-29 WARNING odoo919 odoo.osv.expression: Unexpected domain [('id', 'parent_of', False)], interpreted as False
res.partner()