目录
[Object Type](#Object Type)
[Action Type](#Action Type)
到目前为止,我们主要通过声明字段和视图来构建模块。在上一章中,我们通过计算字段和 onchanges 引入了业务逻辑。在任何实际业务场景中,我们都希望将一些业务逻辑与操作按钮联系起来。在我们的房地产示例中,我们希望能够:
- 取消或设置为已售出
- 接受或拒绝offer
有人会说,我们已经可以通过手动更改状态来完成这些工作,但这样做并不方便。此外,我们还想增加一些额外的处理过程:当报价被接受时,我们想设置房产的售价和买家。
Object Type
在我们的房地产模块中,我们希望将业务逻辑与一些按钮联系起来。最常见的方法是
-
在视图中添加一个按钮,例如在视图的标题中:
<form><button name="action_do_something" type="object" string="Do Something"/> <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_doo_something" 的 Python 方法。
需要注意的第一个重要细节是,我们的方法名称前没有下划线 (_)。这使得我们的方法成为一个公共方法,可以直接从 Odoo 接口调用(通过 RPC 调用)。到目前为止,我们创建的所有方法(compute、onchange)都是内部调用的,因此我们使用了以下划线为前缀的私有方法。除非需要从用户界面调用,否则应始终将方法定义为私有方法。
还要注意的是,我们在 self 上循环。一定要假设一个方法可以在多条记录上调用,这样更有利于重用。
最后,公共方法应始终返回一些内容,以便通过 XML-RPC 调用。如果有疑问,只需返回 True 即可。
实践:给房产详情增加sold和cancel按钮
<header>
<button class="oe_highlight" name="action_sold" type="object" string="Sold" />
<button class="btn-danger" name="action_cancel" type="object" string="Cancel" />
</header>
在estate_property模型中加入以下action:
def action_sold(self):
for record in self:
if record.state == "canceled":
raise UserError("You can't sell a canceled property")
record.state = "sold"
def action_cancel(self):
for record in self:
if record.state == "sold":
raise UserError("You can't cancel a sold property")
record.state = "canceled"
效果如下:
实践:给Offer增加接受和取消按钮
<record id="estate_property_offer_view_tree" model="ir.ui.view">
<field name="name">offers</field>
<field name="model">estate_property_offer</field>
<field name="arch" type="xml">
<tree string="offers">
<field name="price"/>
<field name="partner_id"/>
<field name="validity"/>
<field name="date_deadline"/>
<button name="action_confirm" string="Confirm" type="object" icon="fa-check"/>
<button name="action_refuse" string="Cancel" type="object" icon="fa-times"/>
<field name="status"/>
</tree>
</field>
</record>
在estate_property_offer模型中增加相应的action:
def action_confirm(self):
for record in self:
record.status = "accepted"
record.property_id.partner_id = record.partner_id
record.property_id.selling_price = record.price
record.property_id.state = "offer_accepted"
def action_refuse(self):
for record in self:
record.status = "refused"
效果如下图所示
Action Type
在之前的文章中,我们创建了一个与菜单相连的操作。您可能想知道是否可以将动作链接到按钮。好消息是,可以!一种方法是:
<button type="action" name="%(test.test_model_action)d" string="My Action"/>
我们使用 type="action",并在名称中引用外部标识符。
为什么是test.test_model_action
假设有一个模块名为test
,并且在这个模块中定义了一个动作(action)test_model_action
。下面是这个假设模块的一个基本目录结构,以及如何在这个结构中定义和引用test_model_action
:
test/
├── __init__.py
├── __manifest__.py
├── models/
│ └── __init__.py
│ └── model.py
├── views/
│ └── action_view.xml
├── security/
│ └── ir.model.access.csv
└── data/
└── demo_data.xml
test是模块名字,也是命名空间,为了防止action名字和其他模块冲突