建立一個Odoo Module (三)- Inheritance

inheritance 繼承

Model inheritance

Odoo 提供了兩種繼承機制(in a module way),用以繼承已有的model。
第一種機制允許一個 module 去修改定義在另一個 module 的 model:

  • 添加一個新的 fields 到該 model
  • 複寫 fields 的定義
  • 給這個 model 添加限制條件
  • 添加一個新的 method
  • 複寫 model 已有的 method

第二種繼承機制(delegation)The second inheritance mechanism (delegation) allows to link every record of a model to a record in a parent model, and provides transparent access to the fields of the parent record.
這裏寫圖片描述

View inheritance

爲了避免直接修改views(修改源文件),Odoo 提供了 view 的繼承機制, where children “extension” views are applied on top of root views, and can add or remove content from their parent.
一個擴展的view,需要使用inherit_id 來指明其 parent 的id,並且,在它的 arch field 中,使用 xpath 元素來選擇和修改parent view。

<!-- improved idea categories list -->
<record id="idea_category_list2" model="ir.ui.view">
    <field name="name">id.category.list2</field>
    <field name="model">idea.category</field>
    <field name="inherit_id" ref="id_category_list"/>
    <field name="arch" type="xml">
        <!-- find field description and add the field
             idea_ids after it -->
        <xpath expr="//field[@name='description']" position="after">
          <field name="idea_ids" string="Number of ideas"/>
        </xpath>
    </field>
</record>
  • expr
    一個 XPath 選擇表達式, 如果在parent view中找不到符合表達式要求的元素,或者多個符合要求的元素, 將直接報錯!
  • position
    如果找到符合要求的 element,那麼將在 element 的什麼位置,對其進行修改
    • inside<xpath> body 的內容,append到符合 expr 的 element 的裏面
    • replace<xpath> body 的內容 replace 符合 expr 的 element
    • before<xpath> body 的內容 insert到 符合 expr 的 element 的前面, 作爲 element的 sibling
    • after<xpath> body 的內容 insert到 符合 expr 的 element 的後面, 作爲 element的 sibling
    • attributes<attribute> 來 修改 element 的 屬性
<!-- 這兩種方法是同樣的效果, 當且僅當 parent view 只有一個滿足要求的field -->
<xpath expr="//field[@name='description']" position="after">
    <field name="idea_ids" />
</xpath>

<field name="description" position="after">
    <field name="idea_ids" />
</field>

練習 3-1

  • 通過使用 Model inheritance, 修改已經存在的 Partner model,給其添加一個 boolean field instructor 和一個 many2many 的字段,用以表示 Partner 與 Session 之間的關係
  • 使用 View inheritance,將這兩個字段展現在 Partner 的 Form view 中

提示:
這個需要開啓 debug 模式,用以找尋 partner form view 的 external id。

openacademy/__init__.py

# -*- coding: utf-8 -*-
from . import controllers
from . import models
# 新增
from . import partner
# 結束

openacademy/__openerp__.py

        # 'security/ir.model.access.csv',
        'templates.xml',
        'views/openacademy.xml',
        # 新增
        'views/partner.xml',
        # 結束
    ],
    # only loaded in demonstration mode
    'demo': [

openacademy/partner.py

# -*- coding: utf-8 -*-
from openerp import fields, models

class Partner(models.Model):
    _inherit = 'res.partner'

    # Add a new column to the res.partner model, by default partners are not
    # instructors
    instructor = fields.Boolean("Instructor", default=False)

    session_ids = fields.Many2many('openacademy.session',
        string="Attended Sessions", readonly=True)

openacademy/views/partner.xml

<?xml version="1.0" encoding="UTF-8"?>
 <openerp>
    <data>
        <!-- Add instructor field to existing view -->
        <record model="ir.ui.view" id="partner_instructor_form_view">
            <field name="name">partner.instructor</field>
            <field name="model">res.partner</field>
            <field name="inherit_id" ref="base.view_partner_form"/>
            <field name="arch" type="xml">
                <notebook position="inside">
                    <page string="Sessions">
                        <group>
                            <field name="instructor"/>
                            <field name="session_ids"/>
                        </group>
                    </page>
                </notebook>
            </field>
        </record>

        <record model="ir.actions.act_window" id="contact_list_action">
            <field name="name">Contacts</field>
            <field name="res_model">res.partner</field>
            <field name="view_mode">tree,form</field>
        </record>
        <menuitem id="configuration_menu" name="Configuration"
                  parent="main_openacademy_menu"/>
        <menuitem id="contact_menu" name="Contacts"
                  parent="configuration_menu"
                  action="contact_list_action"/>
    </data>
</openerp>

Domains

在 Odoo 中,Domains 就是給 record 添加各種限制條件的。 一個 domain 就是由一些針對 model 的所有record 進行篩選的 各種條件的 集合。每一個條件都是由 3個元素組成,(field_name, operator, value)
比如:我們要針對 Product model ,篩選出 類型爲 服務(service), 且 unit price 大於 1000

[('product_type', '=', 'service'), ('unit_price', '>', 1000)]

上面條件被默認的添加了一個 隱式的 AND。通過 &(AND),|(OR),!(NOT)可以將複雜的條件組合起來,但是這些邏輯運算符 是在各種條件的前面,而不是在中間。比如:我們尋找 要麼類型爲 service 的product, 要麼 unit_price 不在 1000 到 2000之間的 product。

['|',
    ('product_type', '=', 'service'),
    '!', '&',
            ('unit_price', '>=', 1000),
            ('unit_price', '<=', 2000)]

domain 參數 可以被添加到 relational fields 中,用來在選擇時,只提供給你符合要求的record


練習 3-2
當爲session 選擇 instructor 時,只有 instructor == True 的partner 才被顯示出來
openacademy/models.py

    duration = fields.Float(digits=(6, 2), help="Duration in days")
    seats = fields.Integer(string="Number of seats")
    # 新增
    instructor_id = fields.Many2one('res.partner', string="Instructor",
        domain=[('instructor', '=', True)])
    # 結束
    course_id = fields.Many2one('openacademy.course',
        ondelete='cascade', string="Course", required=True)
    attendee_ids = fields.Many2many('res.partner', string="Attendees")

注意:
如果 domain 被定義成 list 的樣式(明確的python list 類型),將在服務器端被解釋運行, 那麼 條件中的 right value 必須是定死的,不能是動態的value。
如果 domain 被定義成 str(list),將在客戶端解釋運行,那麼條件中的 right value 可以是 field 的 names
其實就是 .py 文件中的domain , 和 xml file 中的domain 有細微差別

練習 3-3
創建兩個partner的category,分別爲:Teacher/Level 1 、Teacher/Level 2。修改session中的instrutor,使其可以爲 partner 中 instructor ==True的,或者 category 爲 Teacher的
openacademy/models.py

    seats = fields.Integer(string="Number of seats")

    instructor_id = fields.Many2one('res.partner', string="Instructor",
        # 修改
        domain=['|', ('instructor', '=', True),
                     ('category_id.name', 'ilike', "Teacher")])
        # 結束
    course_id = fields.Many2one('openacademy.course',
        ondelete='cascade', string="Course", required=True)
    attendee_ids = fields.Many2many('res.partner', string="Attendees")

openacademy/views/partner.xml

        <menuitem id="contact_menu" name="Contacts"
                  parent="configuration_menu"
                  action="contact_list_action"/>

        <!-- 新增 -->
        <record model="ir.actions.act_window" id="contact_cat_list_action">
            <field name="name">Contact Tags</field>
            <field name="res_model">res.partner.category</field>
            <field name="view_mode">tree,form</field>
        </record>
        <menuitem id="contact_cat_menu" name="Contact Tags"
                  parent="configuration_menu"
                  action="contact_cat_list_action"/>

        <record model="res.partner.category" id="teacher1">
            <field name="name">Teacher / Level 1</field>
        </record>
        <record model="res.partner.category" id="teacher2">
            <field name="name">Teacher / Level 2</field>
        </record>
        <!-- 結束 -->
    </data>
</openerp>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章