跳至内容

老赵解读Odoo 18开发教程12:继承与扩展

2026年8月15日
老赵解读Odoo 18开发教程12:继承与扩展

原文:Odoo 18 官方开发教程“Server framework 101”第 12 章。本文尽量保留原文结构、代码、练习与图片,仅进行中文翻译,并在文末增加“老赵解读”。

第12章:继承


Odoo 的一个强大的方面是它的模块化。模块专用于业务需求,但是
模块之间还可以交互。这对于扩展现有的功能很有用
模块。例如,在我们的房地产场景中,我们想要显示销售人员的房产的列表
直接在常规用户视图中。

但在讨论具体的 Odoo 模块继承之前,让我们看看如何改变
标准 CRUD(创建、检索、更新或删除)方法的行为。

Python继承

说明

目标: 在本节末尾:

  • 不应该删除不是新的或已取消的房产。

Unlink

  • 创建报价后,房产状态应更改为“报价已接收”
  • 不可能以低于现有报价的价格创建报价

Create

在我们的房地产模块中,我们从来不需要开发任何特定的东西来能够做到这一点
标准 CRUD 操作。 Odoo 框架提供了必要的
完成这些任务的工具。事实上,这样的动作已经包含在我们的模型中了,感谢经典
Python继承:

from odoo import fields, models

class TestModel(models.Model):
    _name = "test_model"
    _description = "Test Model"

    ...

我们的 class TestModel 继承自 Model ,它提供了
create()read()write()
unlink()

这些方法(以及 Model 上定义的任何其他方法)可以扩展以添加
具体业务逻辑:

from odoo import fields, models

class TestModel(models.Model):
    _name = "test_model"
    _description = "Test Model"

    ...

    @api.model
    def create(self, vals):
        # Do some business logic, modify vals...
        ...
        # Then call super to execute the parent method
        return super().create(vals)

装饰器 model() 对于 create() 是必需的
方法,因为记录集 self 的内容与创建上下文无关,
但对于其他 CRUD 方法则不需要。

同样重要的是要注意,即使我们可以直接覆盖
unlink() 方法,您几乎总是想编写一个新方法
改为装饰器 ondelete() 。用这个装饰器标记的方法将是
unlink() 期间调用并避免在期间可能发生的一些问题
当直接覆盖unlink()时,卸载模型的模块。

在 Python 3 中,super() 相当于 super(TestModel, self)。后者可能是必要的
当您需要使用修改后的记录集调用父方法时。

危险

  • 这是非常重要的 总是 调用 super() 以避免中断流程。有
    只有少数非常具体的情况你不想调用它。
  • 确保 总是 返回数据与父方法一致。例如,如果
    父方法返回 dict(),您的重写也必须返回 dict()

练习

将业务逻辑添加到 CRUD 方法。

  • 如果状态不是“新建”或“已取消”,则防止删除房产

提示:使用 ondelete() 装饰器创建一个新方法并记住
self 可以是具有多个记录的记录集。

  • 在创建报价时,将房产状态设置为“报价已接收”。如果用户也发出错误
    尝试创建金额低于现有报价的报价。

提示:property_id字段在 vals 中可用,但它是 int。至
实例化 estate.property 对象,使用 self.env[model_name].browse(value)
(例子)

模型继承

参考:与该主题相关的文档可以在以下位置找到
继承与延伸

在我们的房地产模块中,我们希望显示链接到销售人员的房产列表
直接在“设置”/“用户和公司”/“用户”表单视图中。为此,我们需要添加一个字段到
res.users模型并调整其视图以显示它。

Odoo 提供了两个 继承 以模块化方式扩展现有模型的机制。

第一个继承机制允许模块修改定义在模型中的行为
另一个模块:

  • 将字段添加到模型,
  • 覆盖模型中字段的定义,
  • 添加约束到模型,
  • 添加方法到模型,
  • 覆盖模型中的现有方法。

第二个继承机制(委托)允许链接模型的每个记录
到父模型的记录并提供对
此父级记录的字段。

Inheritance Methods

在 Odoo 中,第一种机制是迄今为止使用最多的。在我们的例子中,我们想要将字段添加到
现有的模型,这意味着我们将使用第一种机制。例如:

from odoo import fields, models

class InheritedModel(models.Model):
    _inherit = "inherited.model"

    new_field = fields.Char(string="New Field")

添加两个字段的实际示例
可以找到模型
这里

按照约定,每个继承的模型都在其自己的 Python 文件中定义。在我们的例子中,它将是
models/inherited_model.py

练习

将字段添加到用户。

  • 将以下字段添加到 res.users
字段 类型
属性ID 引用销售人员的字段的 One2many 逆 estate.property
  • 将域添加到字段,以便它仅列出可用的房产。

在下一节中,我们将字段添加到视图中并检查一切是否正常!

查看继承

参考:与该主题相关的文档可以在以下位置找到
继承

说明

目标:在本节末尾,可用的房产链接的列表
销售人员应显示在其用户表单视图中

Users

Odoo 不是直接修改现有视图(通过覆盖它们)
提供视图继承,其中子“扩展”视图应用在
根视图。这些扩展程序可以在其父视图中添加和删除内容。

扩展视图使用 inherit_id字段引用其父视图。
它的 arch字段不是单个视图,而是包含许多
xpath 选择和更改其父视图内容的元素:

<record id="inherited_model_view_form" model="ir.ui.view">
    <field name="name">inherited.model.form.inherit.test</field>
    <field name="model">inherited.model</field>
    <field name="inherit_id" ref="inherited.inherited_model_view_form"/>
    <field name="arch" type="xml">
        <!-- find field description and add the field
             new_field after it -->
        <xpath expr="//field[@name='description']" position="after">
          <field name="new_field"/>
        </xpath>
    </field>
</record>
expr
X路径 表达式选择父视图中的单个元素。
如果没有匹配任何元素或匹配多个元素,则会引发错误
position
应用于匹配元素的操作:
`inside`
:   将 `xpath` 的主体附加到匹配元素的末尾

`replace`
:   用 `xpath` 的主体替换匹配的元素,替换任何 `$0` 节点出现
    在带有原始元素的新主体中

`before`
:   将 `xpath` 的主体作为同级元素插入到匹配元素之前

`after`
:   将 `xpaths` 的主体作为同级元素插入到匹配元素之后

`attributes`
:   使用特殊的改变匹配元素的属性
    `xpath` 主体中的 `attribute` 元素

匹配单个元素时,可以直接设置 position属性
在要查找的元素上。下面的两个继承具有相同的结果。

<xpath expr="//field[@name='description']" position="after">
    <field name="idea_ids" />
</xpath>

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

可以找到视图继承扩展的示例
这里

练习

将字段添加到用户视图。

property_ids字段添加到新笔记本页面中的 base.view_users_form 中。

提示:可以找到用户视图继承的示例
这里

由于其模块化概念,继承在 Odoo 中被广泛使用。不要犹豫,阅读
相应的文档以获取更多信息!

下一章中,我们将学习如何
与其他模块交互。

老赵解读

继承让我们在不修改原模块源码的前提下扩展模型、方法和视图,这是 Odoo 生态能够持续组合的关键机制。它既适合给现有模型增加能力,也适合抽取可复用的抽象模型。

覆盖方法时应尽量调用 super(),只改变确实需要改变的部分,并控制模块加载顺序。直接复制整个父方法虽然短期方便,却会让上游升级修复无法自然继承,长期维护成本很高。

老赵解读Odoo 18开发教程11:完善交互体验