You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用bus.bus连接Python与JS?求机制及代码实现方案

使用bus.bus实现Python与JS的双向触发(Odoo环境)

一、单个用户触发:Python调用后触发指定客户端函数

Python端代码调整

你的模型函数里,用_sendone给指定用户发消息即可,需明确用户ID、唯一频道和带类型的消息体,确保JS端能精准识别:

from odoo import models

class MyModel(models.Model):
    _name = 'my.model'
    _description = 'My Model'

    def my_func(self):
        # 先执行你的业务逻辑
        # 发送触发消息
        target_user_id = self.env.user.id  # 可替换为目标用户ID
        # 自定义唯一频道,建议用模型+记录ID,避免频道冲突
        channel = f'my.model.trigger.{self.id}'
        # 消息体带type字段,方便JS区分事件类型
        message = {
            'type': 'call_test',
            'record_id': self.id  # 可选:给JS传递额外业务数据
        }
        self.env['bus.bus']._sendone(target_user_id, channel, message)

JS端绑定事件

在组件中利用Odoo全局bus订阅对应频道,收到指定类型消息时调用test(),注意组件销毁时取消订阅,避免内存泄漏:

import { Component } from "@odoo/owl";
import { bus } from "@web/core/bus";

export class MyComponent extends Component {
    setup() {
        super.setup();
        // 订阅与Python端完全一致的频道(假设组件可获取当前记录ID)
        this.channel = `my.model.trigger.${this.props.record.id}`;
        // 绑定消息处理函数
        this.subscription = bus.subscribe(this.channel, this.onMessageReceived.bind(this));
    }

    onMessageReceived(message) {
        // 仅处理我们需要的事件类型
        if (message.type === 'call_test') {
            this.test();
            // 可直接使用Python传递的额外数据,如message.record_id
        }
    }

    test() {
        console.log('works');
    }

    willUnmount() {
        // 组件卸载时必须取消订阅
        this.subscription.unsubscribe();
    }
}

二、全局广播:向所有活跃用户触发JS函数

要给所有在线用户发消息,用_sendbroadcast替代_sendone,无需指定用户,所有订阅对应频道的客户端都会收到:

Python端广播代码

def broadcast_to_all(self):
    # 先执行业务逻辑
    # 定义全局频道
    global_channel = 'my.model.global.broadcast'
    message = {
        'type': 'global_call_test',
        'notice': '这是给所有用户的通知'
    }
    self.env['bus.bus']._sendbroadcast(global_channel, message)

JS端订阅全局频道

在组件中额外订阅全局频道即可:

setup() {
    super.setup();
    // 订阅全局频道
    this.globalChannel = 'my.model.global.broadcast';
    this.globalSub = bus.subscribe(this.globalChannel, this.onGlobalMessage.bind(this));

    // 保留单个用户的频道订阅(如有需要)
    this.channel = `my.model.trigger.${this.props.record.id}`;
    this.subscription = bus.subscribe(this.channel, this.onMessageReceived.bind(this));
}

onGlobalMessage(message) {
    if (message.type === 'global_call_test') {
        console.log(message.notice);
        this.test(); // 触发全局函数
    }
}

willUnmount() {
    this.subscription.unsubscribe();
    this.globalSub.unsubscribe();
}

三、bus.bus使用实用建议

  • 频道命名规范:采用模块名.模型名.用途.标识格式(如my_module.my.model.record.123),避免与其他模块频道冲突,便于后期维护。
  • 消息结构统一:所有消息必须携带type字段,JS端通过type区分不同事件,禁止传递无结构的零散数据,防止逻辑混乱。
  • 订阅生命周期管理:组件挂载时订阅,卸载时必须取消订阅,避免用户切换页面后仍收到无效消息,引发内存泄漏或逻辑错误。
  • 权限控制:发送消息前验证用户权限,比如禁止普通用户触发管理员专属通知,防止敏感数据泄露。
  • 幂等性处理:若业务场景需避免重复执行,给消息添加唯一ID,JS端记录已处理的ID,防止重复触发逻辑。
  • 调试技巧:Python端用self.env['bus.bus']._log(message)打印消息日志,JS端直接console.log(message),快速排查问题。

内容的提问来源于stack exchange,提问作者Wald Sin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 22:59:59