Skip to content

Latest commit

 

History

History
 
 

demo_hierarchy_tutorial

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

odoo hierarchy 實作

建議觀看影片, 會更清楚:smile:

建議在閱讀這篇文章之前, 請先確保了解看過以下的文章 (因為都有連貫的關係)

odoo 手把手建立第一個 addons

主要介紹 odoo 中如何實現 階層(hierarchy) 的關係.

說明

之前不管是介紹 Many2one 還是 One2many, 都是對別的 model 產生關聯,

那有沒有和自己產生關聯的呢:smile:

答案是有的哦, 就是 odoo 中的 階層(hierarchy) 的關係:satisfied:

階層(hierarchy) 的關係範例圖如下,

alt tag

接著來看教學的範例,

models/models.py

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_idchild_ids 都關聯到同一個 model (也就是自己本身 demo.hierarchy),

然後一個是 Many2one parent_id 和 One2many child_ids.

views/view.xml

<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 先不填

alt tag

點選 add 再建立一比 demo.hierarchy (test2)

alt tag

呈現效果如下, test2 的 parent 就是 test1

alt tag

點選 add 再建立一比 demo.hierarchy (test3),

呈現效果如下, test2 和 test1 的 parent 都是 test1

alt tag

tree 的部份

alt tag

db 中的狀態

alt tag

說明 child_of 和 parent_of

在 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的關係.

階層關係如下

alt tag

db 關係如下

alt tag

階層關係如下

alt tag

db 關係如下

alt tag

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()