第 9 章:准备好采取行动了吗?

到目前为止,我们主要通过声明字段和视图来构建模块。在 上一章 中,我们借助计算字段和 onchange 初步引入了业务逻辑。在任何真实的业务场景中,我们都希望将一些业务逻辑关联到动作按钮上。在我们的房地产示例中,我们希望能够:

  • 取消房产或将房产设为已售

  • 接受或拒绝报价

有人可能会说,我们只要手动更改状态就已经能做到这些,但这并不太方便。此外,我们还想添加一些额外的处理:当报价被接受时,我们希望设置房产的售价和买家。

对象类型

参考:与本主题相关的文档可在 操作 和 错误管理 中找到。

注解

目标:本节结束时:

  • 你应该能够取消房产或将房产设为已售:

取消并设为已售

已取消的房产不能设为已售,已售的房产也不能取消。为清晰起见,视图中已添加 state 字段。

  • 你应该能够接受或拒绝报价:

接受或拒绝报价
  • 报价被接受后,应设置售价和买家:

接受报价

在我们的房地产模块中,我们希望将业务逻辑与一些按钮关联起来。最常见的做法是:

  • 在视图中添加一个按钮,例如在视图的 header 中:

<form>
    <header>
        <button name="action_do_something" type="object" string="Do Something"/>
    </header>
    <sheet>
        <field name="name"/>
    </sheet>
</form>
  • 然后将此按钮关联到业务逻辑:

from odoo import fields, models

class TestAction(models.Model):
    _name = "test.action"

    name = fields.Char()

    def action_do_something(self):
        for record in self:
            record.name = "Something"
        return True

通过为按钮指定 type="object",Odoo 框架将在给定模型上执行名为 name="action_do_something" 的 Python 方法。

首先要说明的重要细节是,我们的方法名没有以下划线(_)为前缀。这使得该方法成为 公有 方法,可以直接从 Odoo 界面(通过 RPC 调用)调用。到目前为止,我们创建的所有方法(compute、onchange)都是内部调用的,因此我们使用的是以下划线为前缀的 私有 方法。除非方法需要从用户界面调用,否则应始终将其定义为私有方法。

另请注意,我们遍历了 self。要始终假设方法可能在多条记录上被调用;这更有利于复用。

最后,公有方法应始终返回一些内容,以便能通过 XML-RPC 调用。拿不准时,直接 return True 即可。

Odoo 源代码中有数百个示例。其中一个示例是这个 视图中的按钮 及其 对应的 Python 方法

练习

取消房产并将其设为已售。

  • 向 estate.property 模型添加 ‘Cancel’ 和 ‘Sold’ 按钮。已取消的房产不能设为已售,已售的房产也不能取消。

    预期结果请参见 目标 中的第一张图。

    提示:为了引发错误,你可以使用 UserError 函数。Odoo 源代码中有大量示例 ;-)

  • 向 estate.property.offer 模型添加 ‘Accept’ 和 ‘Refuse’ 按钮。

    预期结果请参见 目标 中的第二张图。

    提示:如果想用图标作为按钮,请看一下 这个示例。

  • 当报价被接受时,为该报价对应的房产设置买家和售价。

    预期结果请参见 目标 中的第三张图。

    请注意:在现实中,同一房产只能接受一个报价!

动作类型

在 第 5 章:终于有点界面可以玩了 中,我们创建了一个与菜单关联的动作。你可能想知道是否可以将动作关联到按钮。好消息是,可以!一种做法是:

<button type="action" name="%(test.test_model_action)d" string="My Action"/>

我们使用 type="action",并在 name 中引用 外部标识符。

在 下一章 中,我们将了解如何防止在 Odoo 中录入错误的数据。