第九章 动作(Actions)
篇别:第一篇 基础知识
本章学习目标
- 区分 窗口动作、服务器动作、客户端动作、报表动作、URL 动作 的适用场景。
- 能熟练配置
ir.actions.act_window的context、domain、view_mode、target。 - 会使用 binding 将动作挂到列表/表单的 Action 菜单。
- 理解 动作与菜单、按钮 的引用关系及常见调试方法。
导读:动作是「下一步去哪」
动作(Action) 描述用户或系统触发后 打开什么界面、执行什么逻辑、生成什么报表。菜单、按钮、doAction、定时任务等最终常归结为 返回或引用一条 ir.actions.* 记录。
9.1 窗口动作(ir.actions.act_window)
9.1.1 知识要点
| 字段 | 作用 |
|---|---|
res_model |
目标模型 |
view_mode |
如 list,form 顺序影响默认打开 |
view_id / search_view_id |
指定具体视图记录(可选) |
domain |
预置过滤域 |
context |
默认值、search_default_*、活跃公司等 |
target |
current / fullscreen / new(弹窗) |
res_id |
直接打开某条记录(少用) |
limit |
列表每页条数(若支持) |
9.1.2 案例
案例 A:基础列表+表单
<record id="action_library_book" model="ir.actions.act_window">
<field name="name">图书</field>
<field name="res_model">library.book</field>
<field name="view_mode">list,form,kanban</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">创建第一本书</p>
</field>
</record>
案例 B:带 domain 与 context
<field name="domain">[('state','!=','archived')]</field>
<field name="context">{
'default_state': 'draft',
'search_default_available': 1
}</field>
案例 C:弹窗向导
<field name="target">new</field>
<field name="view_mode">form</field>
<field name="res_model">library.loan.wizard</field>
9.1.3 截图占位


9.1.4 本节练习
- 实操:新建动作仅
kanban模式打开图书。 - 简答:
context中的active_id何时由框架注入? - 判断:
domain可被用户在 UI 完全移除后绕过。( )
参考答案提示:3. 对 UI 可改;敏感过滤须 记录规则 或 方法内校验。
9.2 服务器动作(ir.actions.server)
9.2.1 知识要点
- 绑定模型:
model_id;代码中可操作records或env(依「执行代码」类型)。 - 用途:自动化、批量标记、创建活动、触发向导;复杂逻辑仍建议 模型方法 + 服务器动作仅调用一行。
- 风险:Python 字符串存在 升级与环境漂移;生产需 权限与审计。
9.2.2 案例
界面创建(描述性):模型 library.book,动作「执行 Python 代码」:
records.write({'state': 'archived'})
XML 定义(示意)
<record id="action_server_archive_books" model="ir.actions.server">
<field name="name">批量归档</field>
<field name="model_id" ref="model_library_book"/>
<field name="state">code</field>
<field name="code">
if records:
records.write({'state': 'archived'})
</field>
</record>
9.2.3 截图占位

9.2.4 本节练习
- 简答:服务器动作相对「菜单调
object方法」的优缺点? - 实操:创建服务器动作:给选中图书记录
message_post一条内部备注(需mail.thread)。 - 安全:谁可以编辑
ir.actions.server?如何限制?
参考答案提示:1. 低代码快 vs 难测难版本管理。3. 仅设置/技术管理员;可用组隔离。
9.3 客户端动作(ir.actions.client)
9.3.1 知识要点
tag:对应前端注册的 client action 名称。- 用于 仪表盘、全屏自定义页;需
assets注册 JS 与 OWL 入口。
9.3.2 案例(思路)
- JS:
registry.category("actions").add("my_dashboard", MyDashboardAction); - XML:
<field name="tag">my_dashboard</field>
详见第三十二章、第三十五章。
9.3.3 截图占位

9.3.4 本节练习
- 拓展:在源码搜索
registry.category("actions"),记录一个内置tag。 - 简答:client action 与
act_window打开res_model的差异?
9.4 报表动作(ir.actions.report)
9.4.1 知识要点
report_name:QWeb 模板名;report_type:qweb-pdf、qweb-html等。paperformat_id:纸张;binding_model_id:绑定到模型的打印菜单。- 打印:用户界面「打印」触发;同样受 记录权限 约束。
9.4.2 案例
<record id="action_report_book_card" model="ir.actions.report">
<field name="name">图书卡片</field>
<field name="model">library.book</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">my_library.report_book_document</field>
<field name="binding_model_id" ref="model_library_book"/>
<field name="binding_type">report</field>
</record>
9.4.3 截图占位

9.4.4 本节练习
- 实操:实现最小 QWeb PDF(可对接第十九章)。
- 简答:
binding_type=report与action的区别?
9.5 URL 动作(ir.actions.act_url)
9.5.1 知识要点
打开 外部或内部 URL;target:new 新标签,self 当前窗口(易打断 SPA,慎用)。
9.5.2 案例
<record id="action_doc_odoo" model="ir.actions.act_url">
<field name="name">Odoo 19 文档</field>
<field name="url">https://www.odoo.com/documentation/19.0/developer.html</field>
<field name="target">new</field>
</record>
内部深度链接(示例,以实际路由为准):
<field name="url">/web#action=123&model=library.book&view_type=list</field>
9.5.3 截图占位

9.5.4 本节练习
- 简答:
target=self的典型用途与风险? - 实操:菜单链到你们公司内部 Wiki(
new)。
参考答案提示:1. 当前页跳转;风险是离开 WebClient 丢 SPA 状态。
9.6 动作绑定(Bindings)(新增)
9.6.1 知识要点
在 ir.actions.act_window 或报表上设置:
binding_model_id:挂到哪个模型。binding_type:action或report。binding_view_types:如list,form;限制在哪些视图出现 Action 菜单。
9.6.2 案例
<record id="action_book_mass_tag" model="ir.actions.act_window">
<field name="name">批量打标签</field>
<field name="res_model">library.book.tag.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="binding_model_id" ref="model_library_book"/>
<field name="binding_view_types">list</field>
</record>
9.6.3 截图占位

9.6.4 本节练习
- 实操:绑定「导出选中 ISBN」向导(TransientModel)。
- 简答:binding 能否替代 ACL?
- 判断:无列表权限的用户看不到 binding 动作,因此也绝对无法创建图书记录。( )
参考答案提示:2. 不能。3. 错,可能通过 API/其他入口。
9.7 动作链与返回值(Python)
9.7.1 知识要点
模型方法可 return:
return {
'type': 'ir.actions.act_window',
'name': _('借阅单'),
'res_model': 'library.loan',
'view_mode': 'list,form',
'domain': [('book_id', '=', self.id)],
'context': {'default_book_id': self.id},
}
或使用 self.env.ref('...').read()[0] 合并修改。
9.7.2 案例
def action_view_loans(self):
self.ensure_one()
action = self.env['ir.actions.act_window']._for_xml_id('my_library.action_library_loan')
action['domain'] = [('book_id', '=', self.id)]
action['context'] = {'default_book_id': self.id}
return action
9.7.3 本节练习
- 实操:Smart button 调上述方法打开过滤后的列表。
- 简答:
_for_xml_id与ref().read()[0]的差异?
本章综合练习
- 画图:菜单点击 →
ir.ui.menu→act_window→ir.ui.view的数据流。 - 判断:
binding可替代 ACL。( ) - 综合:设计「借阅超期」:服务器动作 发邮件 + 客户端动作 看仪表盘,各一条需求说明(不必全实现)。
- 调试:动作打开空白模型——列出检查项(
res_model拼写、模块安装、ACL、动作 id)。
参考答案提示:2. 错。
本章对应白皮书目录:第九章 动作。