Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Dynamic Window Actions in Odoo 14: Server Actions and Programmatic Navigation

Tech May 9 4

Odoo’s ir.actions.act_window enables dynamic navigation to views of models, and when combined with server actions or JavaScript triggers, it allows context-aware filtering and targeted UI behavior.

Defining a Window Action with Custom View References A window action can be declared in XML to specify which views should be used when opening a model, overriding defaults with custom references:

<record id="res_company_user_action" model="ir.actions.act_window">
    <field name="name">Users</field>
    <field name="res_model">res.users</field>
    <field name="view_mode">tree,form,kanban</field>
    <field name="context">
        {
            'form_view_ref': 'ship_manage.res_company_user_view_form',
            'tree_view_ref': 'ship_manage.res_company_user_view_tree',
            'kanban_view_ref': 'ship_manage.res_company_user_view_kanban',
            'search_view_ref': 'ship_manage.res_company_user_view_search'
        }
    </field>
</record>

This configuration ensures that when the action is invoked, Odoo loads the explicitly referenced views instead of relying on the model’s default view definitions.

Filtering Data via Server Actions Server actions can modify the domain of a window action dynamically based on the current user’s context. For instance, to restrict user records to those belonging to the user’s company:

<record model="ir.actions.server" id="res_company_user_server_action">
    <field name="name">Filter Users by Company</field>
    <field name="model_id" ref="base.model_res_users"/>
    <field name="state">code</field>
    <field name="code">
action = env.ref('ship_manage.res_company_user_action').read()[0]
action['domain'] = [('company_id', '=', env.user.company_id.id)]
return action
    </field>
</record>

The server action retrieves the existing window action, modifies its domain to include a company filter, and returns the updated action object. This approach is ideal for scenarios where record-level security via ir.rule is insuffficient or too rigid.

Programmatically Creating Window Actions in Server Code Instead of referencing a predefined action, you can construct one entirely in code:

<record model="ir.actions.server" id="res_company_action1">
    <field name="name">Direct Company Form</field>
    <field name="model_id" ref="base.model_res_company"/>
    <field name="state">code</field>
    <field name="code">
action = {
    'name': 'Company Test',
    'type': 'ir.actions.act_window',
    'res_model': 'res.company',
    'view_mode': 'form',
    'view_type': 'form',
    'target': 'main',
    'res_id': env.user.company_id.id,
    'context': {'form_view_ref': 'ship_manage.res_company_view_form_test'}
}
return action
    </field>
</record>

This method gives full control over the action’s properties — including target, context, and record ID — without requiring a prior XML declaratoin.

Triggering Actions from Python Buttons In a form view, a button can invoke a server method that returns a window action:

<button name="get_company_action" string="Open Company" type="object"/>

def get_company_action(self):
    action = self.env.ref('ship_manage.ship_manage_res_company_action').read()[0]
    action['res_id'] = self.env.user.company_id.id
    return action

Alternative, define the action inline without referencing an XML record:

def get_company_action(self):
    rb = self.env['bill.head'].browse(self.env.context.get('active_id'))
    return {
        'name': _('Repair Bill'),
        'type': 'ir.actions.act_window',
        'res_model': 'bill.head',
        'view_mode': 'form',
        'target': 'main',
        'res_id': rb.id,
        'context': {'form_view_ref': 'ship.bill_head_view_form'}
    }

This approach is useful for actions tied to specific records or dynamic business logic.

Invoking Actions via JavaScript In web client widgets, actions can be triggered using the do_action method. The views parameter defines the sequence and type of views to load:

_onBtnClicked: function (ev) {
    this.do_action({
        type: 'ir.actions.act_window',
        name: this.title,
        res_model: this.modelName,
        views: [[false, 'list'], [false, 'form']],
        domain: ev.data.domain,
    });
}

Here, [false, 'list'] means "use the default tree view," and [false, 'form'] means "use the default form view." To use a specific view ID, replace false with the actual view ID (e.g., [123, 'tree']), which can be obtained via ref in XML or fetched dynamically.

For advanced use cases, such as opening a form view with a specific record and custom context, the same structure applies — just set res_id and extend the context object accordingly.

The core implementation of window actions resides in odoo/odoo/addons/base/models/ir_actions.py, where the ir.actions.act_window model handles view resolution, domain evaluation, and context merging.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.