原模型继承
为模型添加字段
- 通过 Python 类来新建模型,继承模型同样是通过 Python 以及 Odoo 自有的继承机制,即
_inherit
类属性。
- 该属性标明所继承的模型。新的类继承父 Odoo 模型的所有功能,仅需声明要做修改的部分。
- 添加library_member/models/library_book.py文件来继承原模型,首先创建__init__.py文件来导入该文件:
- 添加library_member/init.py文件来导入 models 子文件夹
- 添加library_member/models/init.py文件子文件夹中的代码文件:
1
| from . import library_book
|
- 创建library_member/models/library_book.py文件来继承library.book模型:
1 2 3 4 5 6 7
| from odoo import api, fields, models
class Book(models.Model): _inherit = 'library.book' is_available = fields.Boolean('Is Available?')
|
- 使用
_inherit
类属性来声明所继承模型。注意我们并没有使用到其它类属性,甚至是_name
也没使用。除非想要做出修改,否则不需要使用这些属性。
- 可以把这个想成是对模型定义的一个引用,在原处做了一个修改。
- 可以添加字段、修改已有字段、修改模型类属性甚至是包含业务逻辑的方法。
- 要在数据表中添加新的模型字段需要安装该模块。
修改已有字段
在继承模型时,可对已有字段叠加修改,也就是说仅需定义要增加或修改的字段属性。
我们将对原来创建的library_app模块的Book模型做两处简单修改:
- 为
isbn
字段添加一条提示,说明同时支持10位数的 ISBN
- 为
publisher_id
字段添加数据库索引,以提升搜索效率
- 编辑library_member/models/library_book.py文件,并在
library.book
模型中添加如下代码:
1 2 3 4
| class Book(models.Model): ... isbn = fields.Char(help="Use a valid ISBN-13 or ISBN-10.") publisher_id = fields.Many2one(index=True)
|
修改视图和数据
模块中视图和其它数据构件也可通过继承来修改。就视图而言,通常需要添加功能。视图的展示结构在arch
字段中使用XML
定义。
继承视图
- 表单、列表和搜索视图通过
arch XML
结构定义。要继承视图,就要一种修改XML
的方式,也即定位XML
元素然后对该处进行修改。
- 视图继承的
XML
记录和普通视图中相似,多一个inherit_id
属性来引用所要继承的视图。
- 下面我们来继承图书视图并添加
is_available
字段。
- 首先要查找待继承的视图的
XML ID
,通过"设置 > 技术 > 用户界面 > 视图"菜单来查看。
- 图书表单的
XML ID
是library_app.view_form_book
。然后还要找到要插入修改的XML元素,我们在ISBN
字段之后添加Is Available?
通常通过name
属性定位元素,此处为<field name="isbn"/>
。
- 我们添加views/book_view.xml文件来继承
Partner
视图,加入如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?xml version="1.0"?> <odoo> <record id="view_form_book_extend" model="ir.ui.view"> <field name="name">Book: add Is Available? field</field> <field name="model">library.book</field> <field name="inherit_id" ref="library_app.view_form_book" /> <field name="arch" type="xml">
<xpath expr="//field[@name='isbn']" position="after"> <field name="is_available" /> </xpath> </field> </record> </odoo>
|
inherit_id
记录字段通过ref
属性指向继承视图的外部标识符
- 视图使用
XML
定义并存储在结构字段arch
中。要继承一个视图,先定位要扩展的节点,然后执行要做的操作,如添加XML
元素。
- 定位节点的最简单方法是使用唯一标识属性,
- 通常是
name
。然后添加定位属性,声明要做的修改。本例中继承节点是name="isbn"
元素,修改是在选定元素后加一段XML
:
1 2 3
| <field name="isbn" position="after"> </field>
|
一旦XML
节点被选为继承点,需要指明要执行的继承操作。这通过position
属性实现:
- inside(默认值):在所选节点内添加内容,这一节点应是
<group>
或<page>
一类的容器
- after:在选定节点之后向父节点添加内容
- before:在选定节点之前向父节点添加内容
- replace:替换所选节点。若使用空元素则会删除该元素。Odoo 之后还允许使用其它标记来包裹元素,通过在内容中使用$0来表示被替换的元素。
- attributes:修改匹配元素属性值。内容中应包含带有一个或多个
<attribute name="attr-name">value</attribute>
元素。
- 如
<attribute name="invisible">True</attribute>
,若不带内容,如<attribute name="invisible"/>
则attribute
会从所选元素中删除。
- 通过
position="replace"
可删除XML
元素,但应避免这么做。这么做会破坏其它依赖所删除节点、将其作为占位符添加元素的模块。一个替代方案是,让该元素不可见。
- 除了
attributes
定位,上述定位符可与带position="move"
的子元素合并。效果是将子定位符目标节点移到父定位符目录位置。
例如:
1 2 3
| <field name="target_field" position="after"> <field name="my_field" position="move"/> </field>
|
其它视图类型,如列表和搜索视图,也有’arch`字段,可以表单视图同样的方式被继承。
使用XPath选取继承点
- 有时可能没有带唯一值的属性来用作
XML
节点选择器。在所选元素没有name
属性时可能出现这一情况,如<group>
、<notebook>
或<page>
视图元素。
- 另外就是有多个带有相同
name
属性的元素,比如在看板 QWeb 视图中相同字段可能在同一XML
模板中被多次包含。
- 在这些情况下我们就需要更高级的方式来定位待扩展
XML
元素。定位XML
中元素的一种自然方式是XPath
表达式。
- 以定义的 Book 表单视图为例,定位
<field name="isbn">
元素的 XPath 表达式是//field[@name]='isbn'
。该表达式查找name
属性等于isbn
的<field>
元素。
前一部分对图书表单视图继承的XPath
写法是:
1 2 3
| <xpath expr="//field[@name='isbn']" position="after"> <field name="is_available" /> </xpath>
|
如果XPath
表达式匹配到了多个元素,仅会选取第一个作为扩展目录。所以表达式应越精确越好,使用唯一属性。
name
属性最易于确保找到精确元素作为扩展点,因此在创建视图XML
元素时添加唯一标识符就非常重要。
修改数据
- 普通数据记录不同于视图,它没有
XML arch
结构,也不能使用XPath
来进行扩展。但还是可以通过替换字段值来进行修改。
<record id="x" model="y">
数据加载元素实际是对 y 模型进行插入或更新操作。
- 若不存在记录 x,则被创建,否则被更新/覆盖。其它模块中的记录可通过
<module>.<identifier>
全局标识符访问,因此可以在我们的模块中重写其它模块中已写入的数据。
- 点号是保留符号,用于分隔模块名和对象标识符,所以在标识符名中不要使用点号,而应使用下划线字符。
- 举个例子,我们将
User
安全组的名称修改为Librarian
,对应修改library_app.library_group_user
记录。添加library_member/security/library_security.xml并加入如下代码:
1 2 3 4 5 6
| <odoo> <record id="library_app.library_group_user" model="res.groups"> <field name="name">Librarian</field> </record> </odoo>
|
这里我们使用了一个<record>
元素,仅写name
字段。可以认为这是对所选字段的一次写操作。