Mastering Client-Side RPC Calls and Backend Routing in Odoo 14

Odoo's architecture relies heavily on remote procedure calls to bridge its JavaScript frontend and Python backend. While external API integrations require explicit authentication flows, internal frontend modules—such as custom widgets, dynamic views, or action handlers—communicate directly with the server through the built-in _rpc utility. This guide focuses on implementing internal RPC communications, demonstrating how to invoke custom backend logic, retrieve agrgegated data, and understand the underlying parameter routing mechanism.

When triggering a custom server-side method from a widget, the JavaScript payload must align with the backend signature. Below is a modernized pattern for invoking a custom action handler:

// Initiating a custom backend action
this._rpc({
    model: 'res.users',
    method: 'fetch_user_profile_action',
    args: [this.env.user.id],
}).then((response) => {
    this.do_action(response);
}).catch((error) => {
    console.error('RPC dispatch failed:', error);
});

For retrieving summarized data without loading full records, the read_group method is highly efficient. Here’s how to structure that call using a sales domain:

// Fetching aggregated metrics
this._rpc({
    model: 'sale.order',
    method: 'read_group',
    domain: [['state', '=', 'sale']],
    fields: ['amount_total'],
    groupBy: ['user_id'],
}).then((aggregatedData) => {
    const summaryMap = {};
    aggregatedData.forEach((item) => {
        summaryMap[item.user_id[0]] = item.amount_total;
    });
    this.updateDashboard(summaryMap);
});

On the backend, the corresponding Python method must be decorated appropriately to match the expected signature. For standard record-set operations, @api.model or @api.model_create_multi dictates how Odoo parses incoming arguments:

from odoo import api, models

class Users(models.Model):
    _inherit = 'res.users'

    @api.model
    def fetch_user_profile_action(self, user_id):
        action_ref = self.env.ref('custom_module.action_user_profile_window')
        action_data = action_ref.read()[0]
        action_data['res_id'] = user_id
        return action_data

Understanding how Odoo dispatches RPC requests is crucial for debugging and optimizing custom methods. The framwork inspects the target method's API signature to determine the routing strategy. This logic resides in the core call_kw dispatcher:

def call_kw(model, method_name, args, kwargs):
    """Routes RPC requests based on method API decorators."""
    target_method = getattr(type(model), method_name)
    api_type = getattr(target_method, '_api', None)
    
    if api_type == 'model':
        return _dispatch_model_method(target_method, model, args, kwargs)
    elif api_type == 'model_create':
        return _dispatch_create_method(target_method, model, args, kwargs)
    else:
        return _dispatch_recordset_method(target_method, model, args, kwargs)

When a request arrives, Odoo extracts the context and routes the payload accordingly. For @api.model methods, the entire recordset acts as self, and the args tuple contains the user-supplied parameters. For traditional multi-record methods, the first argument is always interpreted as a list of record IDs, which Odoo automatically conevrts into a recordset via browse(). This abstraction eliminates manual ID-to-recordset conversion but requires developers to align their JavaScript args arrays with the expected backend signature.

Tags: odoo14 javascript python odoo-rpc odoo-framework

Posted on Tue, 08 Sep 2026 16:56:41 +0000 by BillyMako