模型继承
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
xpath
在匹配元素的末尾附加的主体replace
用xpath
的主体替换匹配的元素,用$0
原始元素替换新主体中出现的任何节点before
xpath
在匹配元素之前将的正文作为同级插入after
xpaths
在匹配的元素之后将的正文作为同级插入
attributes
变造使用特殊的匹配元素的属性attribute
的元素的xpath
的身体
匹配单个元素时,
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字段。
使用视图继承,在伙伴表单视图中显示此字段。
(这是引入开发人员模式检查视图,找到其外部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>
<!-- 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"/>
</odoo>
域
在Odoo中,搜索域是对记录条件进行编码的值。域是用于选择模型记录子集的条件列表。每个条件都是一个三元组,其中包含一个字段名称、一个运算符和一个值。
例如,当在产品模型上使用时,以下域会选择单价超过1000的所有服务:
[('product_type', '=', 'service'), ('unit_price', '>', 1000)]
默认情况下,标准和隐式的组合在一起。逻辑运算符&
(AND),|
(OR)和!
(NOT)可用于显式组合条件。它们被用于前缀位置(运算符插入在其参数之前,而不是参数之间)。例如,选择“服务或单价不在1000到2000之间的产品”:
['|',
('product_type', '=', 'service'),
'!', '&',
('unit_price', '>=', 1000),
('unit_price', '<', 2000)]
一个domain参数可以被添加到相关的领域,限制有效记录试图选择在客户端界面记录时的关系。
“关系领域领域”练习
在选择Session的讲师时,只有讲师(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")
声明为文字列表的域在服务器端评估,不能在右侧引用动态值,声明为字符串的域在客户端评估,并允许在右侧使用字段名称
“更复杂的域”练习
创建新的合作伙伴类别“教师/级别1”和“教师/级别2”。会话的讲师可以是任何级别的讲师或老师。
- 修改会话模型的域
- 进行修改openacademy/view/partner.xml以访问 合作伙伴类别:
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
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>
</odoo>