### 繼承
[TOC]
#### 模型繼承
Odoo提供兩種繼承機制,以模塊化方式擴展現有模型。
第一種繼承機制允許一個模塊修改另一個模塊中定義的模型的行為。
* 給模型添加字段
* 覆蓋模型現有字段
* 給模型添加約束
* 給模型添加方法
* 覆蓋模型現有方法
第二種繼承機制(委托)允許將模型的每條記錄鏈接到父模型的記錄,并且提供對父記錄的透明訪問。
#### 視圖繼承
Odoo不是通過覆蓋來修改現有視圖,而是通過視圖繼承。子視圖不僅能夠修改繼承至父視圖的自身內容,而且能夠修改和刪除父視圖中的內容。
擴展視圖使用`inherit_id`字段引用其父代,而不是單個視圖,其`arch`字段由任意數量的`xpath`元素組成,選擇和更改其父視圖的內容:
~~~
<!-- 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*表達式。如果沒有匹配到元素或者匹配到多個元素則引發錯誤。
*position*
對匹配到的元素進行操作。
*inside*
在匹配元素的末尾追加
*before*
作為匹配元素的同級元素添加在其后面
*after*
作為匹配元素的同級元素添加在其前面
*replace*
替換匹配的元素
*attributes*
使用新的屬性替換匹配元素的屬性
> 提示
> 當匹配單個元素時,`position`可以直接在匹配的元素上設置屬性。下面的兩個繼承將給出相同的結果:
~~~
<xpath expr="//field[@name='description']" position="after">
<field name="idea_ids" />
</xpath>
<field name="description" position="after">
<field name="idea_ids" />
</field>
~~~
> 練習更改現有內容
>
> * 使用模型繼承,修改現有*partner*模型,添加`instructor`布爾字段,以及對應表示"授課-講師"關聯的*many2many*字段
> * 使用視圖繼承在*partner*的表單視圖中顯示這個字段
>
> > 注意,這里是通過開發人員模式來查找視圖外部ID并放置新字段的。
>
>
> * 創建文件`openacademy/models/partner.py`并將其導入`__init__.py`
> * 創建文件`openacademy/views/partner.xml`并將其添加到`__manifest__.py`
`openacademy/__init__.py`
~~~
# -*- coding: utf-8 -*-
from . import controllers
from . import models
from . import partner
~~~
`openacademy/__manifest__.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 odoo 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"?>
<odoo>
<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>
</odoo>
~~~
#### Domain
Odoo中,Domain代表記錄集的條件表達式。Domain是定義模型子集的規則集合。每個規則是一個包含名稱、操作和值的三元組。例如,下面是*Product*模型子集的Domain表達式,“單價大于1000且類型為服務”的記錄集:
~~~
[('product_type', '=', 'service'), ('unit_price', '>', 1000)]
~~~
多個規則組合時,默認條件組合方式是AND。邏輯運算符`&(AND)`,`|(OR)`,`!(NOT)`可以用來顯示的組合多個規則。它們在前綴位置使用(操作符在參數之前,而不是中間)。例如下面的Domain表達式,含義是"類型為服務或者單價不介于1000和2000之間"
~~~
['|',
('product_type', '=', 'service'),
'!', '&',
('unit_price', '>=', 1000),
('unit_price', '<', 2000)]
~~~
當在客戶端界面選擇記錄集時,`domain`參數可以添加到關聯字段上,以限制只顯示有效的關聯字段。
> 練習在關聯字段上使用Domain,當為授課選擇講師時,只有`instructor`值為`True`的講師會被顯示出來。
`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會在服務端進行計算,不會出現在右側的動態列表中,而聲明為字符串的domain是在客戶端進行計算的,字段名將出現在右側列表。
>
> 練習更復雜的domain,創建新的*partner*類別*Techer/Level1*和*Techer/Level2*.一個授課的教授人可以是講師或者任意級別的教師。
>
> * 修改*Session*模型的domain
> * 修改`openacademy/view/partner.xml`以獲得訪問*Partner*類別的入口。
`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>
</odoo>
~~~
作者:luohuayong
鏈接:http://www.jianshu.com/p/fd0617835b48
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
- 開發教程
- Odoo10開發教程一(構建模塊)
- Odoo10開發教程二(基本視圖)
- Odoo10開發教程三(模型關聯)
- Odoo10開發教程四(繼承)
- Odoo10開發教程五(計算字段和默認值)
- Odoo10開發教程六(高級視圖)
- Odoo10開發教程七(工作流和安全)
- 參考手冊
- odoo V10中文參考手冊(一:ORM API)
- odoo V10中文參考手冊(指導規范)
- 技巧
- odoo 常用widget
- Odoo(OpenERP)開發實踐:菜單隱藏(1)
- Odoo(OpenERP)開發實踐:菜單隱藏(2)
- Odoo(OpenERP)開發實踐:數據模型學習
- Odoo中自動備份數據庫
- Odoo(OpenERP)應用實踐: 使用db-filter參數實現通過域名指定訪問哪個數據庫
- Odoo(OpenERP)配置文件openerp-server.conf詳解
- Odoo(OpenERP v8)數據模型(Data Model)
- odoo10學習筆記十七:controller
- Qweb定義