Skip to content

12. 操作处理

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

  • 取消或将房产标记为已售出;

  • 接受报价拒绝报价

有人可能会说,通过手动更改状态来实现这些功能,但这并不方便。要添加一些额外处理:当报价被接受时,需要设置房产的售价和买家。

对象类型

开发实践:实现将房产标记为取消已出售的操作:

一旦报价被接受,就应确定售价和买方:

estate模块中,将业务逻辑与某些按钮关联起来。最常见的方法是:在视图中添加一个按钮,例如,在视图的页眉处:

xml
<form>
    <header>
        <button name="action_do_something" type="object" string="Do Something"/>
    </header>
    <sheet>
        <field name="name"/>
    </sheet>
</form>

并将此按钮与业务逻辑关联:

python
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 调用)调用。到目前为止,创建的所有方法(computeonchange)都是在内部调用的,因此使用了以下划线(_)开头的私有方法。除非需要从用户界面调用,否则应始终将方法定义为私有。

注意: 使用 self 进行循环时,应始终假设一个方法可以对多个记录进行调用;这样更有利于方法的复用。

最后,公共方法应始终返回某个值,以便可以通过 XML-RPC 调用。如果不确定,直接返回 True即可。

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

操作类型

在第 5 章节《界面》中,我们创建了一个与菜单关联的操作。可能在想,是否可以将操作与按钮关联起来。当然可以!实现方法之一是:

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

这里使用 type="action",并在名称中引用外部标识符。在下一章中,我们将探讨如何在 Odoo 中防止录入错误数据。

开发实践

实现将房产设置为取消或已售出的操作

  • estate.property 模型中添加“取消”和“已售出”按钮操作。"已取消"的房产无法标记为"已售出",已被标记为“已售出”的房产也无法取消。

  • estate.property.offer 模型中添加“接受”和“拒绝”按钮。

  • 当报价被接受时,房产应关联设定买家和售价,且同一处房产只能接受一份报价。

打开文件:models/property.py ,新增以下两个方法:

python
# 在 `estate.property` 模型中添加“取消”和“已售出”按钮操作。"已取消"的房产无法标记为"已售出",已被标记为“已售出”的房产也无法取消。            
    def action_sold_btn(self):
        """ [已售出]按钮: 对应的操作 """
        for record in self:
            if record.state == 'canceled':
                raise exceptions.UserError("【已取消】状态的记录不能标记为【已售出】")
            if record.state != 'accepted':
                raise exceptions.UserError("只能在报价已接受的状态下标记为【已售出】")
            record.state = 'sold'
            print(f"action_sold_btn.record=> {record.id}")


    def action_cancel_btn(self):
        """ [取消]按钮: 对应的操作 """
        for record in self:
            if record.state == 'sold':
                raise exceptions.UserError("【已售出】状态的记录不能取消")
            record.state = 'canceled'
            print(f"action_cancel_btn.record=> {record.id}")

打开文件:models/property_offer.py ,新增以下两个方法:

python
# 在 `estate.property.offer` 模型中添加“接受”和“拒绝”按钮。
    def action_accepted(self):
        """ 接受报价 """
        for offer in self:
            offer.write({'status': 'accepted'})
            offer.property_id.selling_price = offer.price
            offer.property_id.buyer_id = offer.partner_id
            offer.property_id.write({'state': 'accepted'})

    def action_refused(self):
        """ 拒绝报价 """
        for offer in self:
            offer.write({'status': 'refused'})
最近更新