繼承
模型繼承
Odoo提供兩種繼承機(jī)制,以模塊化方式擴(kuò)展現(xiàn)有模型。
第一種繼承機(jī)制允許一個(gè)模塊修改另一個(gè)模塊中定義的模型的行為荒叼。
- 給模型添加字段
- 覆蓋模型現(xiàn)有字段
- 給模型添加約束
- 給模型添加方法
- 覆蓋模型現(xiàn)有方法
第二種繼承機(jī)制(委托)允許將模型的每條記錄鏈接到父模型的記錄缤削,并且提供對(duì)父記錄的透明訪問(wèn)瘦棋。
視圖繼承
Odoo不是通過(guò)覆蓋來(lái)修改現(xiàn)有視圖,而是通過(guò)視圖繼承鲜棠。子視圖不僅能夠修改繼承至父視圖的自身內(nèi)容肌厨,而且能夠修改和刪除父視圖中的內(nèi)容。
擴(kuò)展視圖使用inherit_id
字段引用其父代豁陆,而不是單個(gè)視圖柑爸,其arch
字段由任意數(shù)量的xpath
元素組成,選擇和更改其父視圖的內(nèi)容:
<!-- 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="http://field[@name='description']" position="after">
<field name="idea_ids" string="Number of ideas"/>
</xpath>
</field>
</record>
expr
在父視圖中選者單個(gè)元素的XPath表達(dá)式盒音。如果沒(méi)有匹配到元素或者匹配到多個(gè)元素則引發(fā)錯(cuò)誤竖配。
position
對(duì)匹配到的元素進(jìn)行操作。
inside
在匹配元素的末尾追加
before
作為匹配元素的同級(jí)元素添加在其后面
after
作為匹配元素的同級(jí)元素添加在其前面
replace
替換匹配的元素
attributes
使用新的屬性替換匹配元素的屬性
提示
當(dāng)匹配單個(gè)元素時(shí)里逆,position
可以直接在匹配的元素上設(shè)置屬性进胯。下面的兩個(gè)繼承將給出相同的結(jié)果:
<xpath expr="http://field[@name='description']" position="after">
<field name="idea_ids" />
</xpath>
<field name="description" position="after">
<field name="idea_ids" />
</field>
練習(xí)更改現(xiàn)有內(nèi)容
- 使用模型繼承,修改現(xiàn)有partner模型原押,添加
instructor
布爾字段胁镐,以及對(duì)應(yīng)表示"授課-講師"關(guān)聯(lián)的many2many字段- 使用視圖繼承在partner的表單視圖中顯示這個(gè)字段
注意,這里是通過(guò)開(kāi)發(fā)人員模式來(lái)查找視圖外部ID并放置新字段的诸衔。
- 創(chuàng)建文件
openacademy/models/partner.py
并將其導(dǎo)入__init__.py
- 創(chuàng)建文件
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代表記錄集的條件表達(dá)式。Domain是定義模型子集的一組規(guī)則笨农。每個(gè)規(guī)則是一個(gè)包含名稱就缆、操作和值的三元組。例如谒亦,下面是Product模型子集的Domain表達(dá)式竭宰,“單價(jià)大于1000且類型為服務(wù)”的記錄集:
[('product_type', '=', 'service'), ('unit_price', '>', 1000)]
多個(gè)規(guī)則組合時(shí)空郊,默認(rèn)條件組合方式是AND。邏輯運(yùn)算符&(AND)
,|(OR)
,!(NOT)
可以用來(lái)顯示的組合多個(gè)規(guī)則切揭。它們?cè)谇熬Y位置使用(操作符在參數(shù)之前狞甚,而不是中間)。例如下面的Domain表達(dá)式廓旬,含義是"類型為服務(wù)或者單價(jià)不介于1000和2000之間"
['|',
('product_type', '=', 'service'),
'!', '&',
('unit_price', '>=', 1000),
('unit_price', '<', 2000)]
當(dāng)在客戶端界面選擇記錄集時(shí)哼审,domain
參數(shù)可以添加到關(guān)聯(lián)字段上,以限制只顯示有效的關(guān)聯(lián)字段孕豹。
練習(xí)在關(guān)聯(lián)字段上使用Domain涩盾,當(dāng)為授課選取講師時(shí),只有
instructor
值為True
的講師會(huì)被顯示出來(lái)励背。
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會(huì)在服務(wù)端進(jìn)行計(jì)算旁赊,不會(huì)出現(xiàn)在右側(cè)的動(dòng)態(tài)列表中,而聲明為字符串的domain是在客戶端進(jìn)行計(jì)算的椅野,字段名將出現(xiàn)在右側(cè)列表终畅。
練習(xí)更復(fù)雜的domain,創(chuàng)建新的partner類別Techer/Level1和Techer/Level2.一個(gè)授課的教授人可以是講師或者任意級(jí)別的教師竟闪。
- 修改Session模型的domain
- 修改
openacademy/view/partner.xml
以獲得訪問(wèn)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>