Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/odoo/documentation/llms.txt

Use this file to discover all available pages before exploring further.

Actions define how the Odoo system responds to user interactions — clicking a menu item, pressing a button, selecting a record, or running a scheduled job. An action tells the client what to do next: open a view, run server-side code, generate a report, redirect to a URL, or trigger a client-side component. Actions can be stored as database records (referenced by ID or external ID) or returned directly as dictionaries from Python methods.

Action Basics

All actions share two mandatory attributes:
AttributeDescription
typeThe action category, e.g. ir.actions.act_window. Determines which other fields are valid.
nameShort human-readable description. May appear in breadcrumbs or button labels.
A client can receive an action in four forms:
  • False — close any open dialog.
  • A string — treated as a client action tag.
  • An integer — load the action record from the database by ID.
  • A dictionary — execute directly as an inline action descriptor.

Bindings

Any action can be bound to a model so it appears in the model’s contextual Action or Print drop-down menu on list and form views:
AttributeDescription
binding_model_idThe model to bind the action to (use model_id for server actions instead).
binding_typeaction (appears in the Action menu, default) or report (appears in the Print menu).
binding_view_typesComma-separated view types: list, form. Defaults to list,form.
<record id="action_estate_property_sold" model="ir.actions.server">
    <field name="name">Mark as Sold</field>
    <field name="model_id" ref="model_estate_property"/>
    <field name="binding_model_id" ref="model_estate_property"/>
    <field name="binding_type">action</field>
    <field name="binding_view_types">list,form</field>
    <field name="state">code</field>
    <field name="code">records.action_sold()</field>
</record>

Window Actions (ir.actions.act_window)

The most common action type. Opens a model through one or more views (list, form, kanban, graph, pivot, etc.).

Fields

FieldDescription
res_model(required) The model to display.
view_modeComma-separated list of view types, e.g. list,form,kanban.
viewsList of (view_id, view_type) pairs; auto-built from view_mode if not set.
res_idWhen view_mode starts with form, opens this specific record ID.
search_view_id(id, name) pair specifying a custom search view.
targetWhere to open the action: current (default), new (dialog), fullscreen, main (clear breadcrumbs).
contextAdditional context dict passed to all views.
domainDomain filter applied to all searches in the action.
limitDefault number of records in list views. Defaults to 80.

Example

<record id="action_estate_property" model="ir.actions.act_window">
    <field name="name">Properties</field>
    <field name="res_model">estate.property</field>
    <field name="view_mode">list,form,kanban</field>
    <field name="domain">[('active', '=', True)]</field>
    <field name="context">{'search_default_available': 1}</field>
    <field name="help" type="html">
        <p class="o_view_nocontent_smiling_face">
            Create your first property listing!
        </p>
    </field>
</record>

Opening a Specific Record in a Dialog

<record id="action_view_property_form" model="ir.actions.act_window">
    <field name="name">Property Details</field>
    <field name="res_model">estate.property</field>
    <field name="view_mode">form</field>
    <field name="target">new</field>
</record>

Returning an Action from Python

def action_view_offers(self):
    return {
        'type': 'ir.actions.act_window',
        'name': 'Offers',
        'res_model': 'estate.property.offer',
        'view_mode': 'list,form',
        'domain': [('property_id', '=', self.id)],
        'context': {'default_property_id': self.id},
        'target': 'current',
    }

Server Actions (ir.actions.server)

Server actions execute Python code or predefined operations on the server when triggered by a user, a button, or an automation rule.

Fields

FieldDescription
model_idThe model the action operates on.
stateWhat the action does: code, object_create, object_write, multi.
codePython code to execute (when state='code'). Exposes env, model, record, records.
child_idsList of sub-actions to run sequentially (when state='multi').
crud_model_idModel to create/update in (when state='object_create' or object_write).

Code Action

<record id="action_send_welcome_email" model="ir.actions.server">
    <field name="name">Send Welcome Email</field>
    <field name="model_id" ref="base.model_res_partner"/>
    <field name="binding_model_id" ref="base.model_res_partner"/>
    <field name="state">code</field>
    <field name="code">
for partner in records:
    template = env.ref('my_module.email_template_welcome')
    template.send_mail(partner.id, force_send=True)
    </field>
</record>
In server action code, the following names are available: env (the ORM environment), model (the model class), record (single record, may be empty), records (all selected records), datetime, dateutil, time, timezone (corresponding Python modules), log (a log(message, level='info') function that records debug information in ir.logging), and UserError (constructor for the UserError exception).

Code Action That Returns a Next Action

A server action code block can define a variable called action, which is then returned to the client as the next action to execute:
<record id="action_open_property_wizard" model="ir.actions.server">
    <field name="name">Open Offer Wizard</field>
    <field name="model_id" ref="model_estate_property"/>
    <field name="state">code</field>
    <field name="code">
action = {
    'type': 'ir.actions.act_window',
    'res_model': 'estate.property.offer.wizard',
    'view_mode': 'form',
    'target': 'new',
    'context': {'default_property_id': record.id},
}
    </field>
</record>

Multi-Action

<record id="action_estate_multi" model="ir.actions.server">
    <field name="name">Validate and Notify</field>
    <field name="model_id" ref="model_estate_property"/>
    <field name="state">multi</field>
    <field name="child_ids" eval="[
        (4, ref('action_mark_sold')),
        (4, ref('action_send_confirmation_email')),
    ]"/>
</record>

Report Actions (ir.actions.report)

Report actions generate PDF or HTML documents from QWeb templates.

Fields

FieldDescription
nameReport name; used as filename if print_report_name is not set.
modelThe model the report is about.
report_nameExternal ID of the QWeb template (e.g. estate.report_property_template).
report_typeqweb-pdf (default) or qweb-html.
print_report_namePython expression returning the filename, e.g. "'Property - %s' % object.name".
binding_model_idBind to a model so the report appears in the Print menu.
paperformat_idMany2one to report.paperformat; defaults to company format.
groups_idMany2many to res.groups; restricts which groups can view or use the report.
multiIf True, the action will not be displayed on a form view.
attachment_useIf True, the report is generated once and re-printed from the stored attachment on subsequent requests.
attachmentPython expression defining the attachment name; the record is accessible as object.

Example

<record id="action_report_estate_property" model="ir.actions.report">
    <field name="name">Property Report</field>
    <field name="model">estate.property</field>
    <field name="report_type">qweb-pdf</field>
    <field name="report_name">estate.report_property_template</field>
    <field name="print_report_name">'Property - %s' % object.name</field>
    <field name="binding_model_id" ref="model_estate_property"/>
    <field name="paperformat_id" ref="base.paperformat_euro"/>
</record>

QWeb Report Template

<template id="report_property_template">
    <t t-call="web.html_container">
        <t t-foreach="docs" t-as="doc">
            <t t-call="web.external_layout">
                <div class="page">
                    <h2 t-field="doc.name"/>
                    <div class="row">
                        <div class="col-6">
                            <strong>Expected Price:</strong>
                            <span t-field="doc.expected_price"/>
                        </div>
                        <div class="col-6">
                            <strong>Postcode:</strong>
                            <span t-field="doc.postcode"/>
                        </div>
                    </div>
                </div>
            </t>
        </t>
    </t>
</template>

URL Actions (ir.actions.act_url)

URL actions redirect the user to an internal or external URL.

Fields

FieldDescription
urlThe address to open.
targetnew (new tab/window, default), self (current window), download (trigger browser download).

Examples

<!-- Open Odoo website in a new tab -->
<record id="action_visit_website" model="ir.actions.act_url">
    <field name="name">Visit Our Website</field>
    <field name="url">https://www.example.com</field>
    <field name="target">new</field>
</record>

<!-- Force-download a file from a controller -->
<record id="action_download_export" model="ir.actions.act_url">
    <field name="name">Download Export</field>
    <field name="url">/estate/export/properties</field>
    <field name="target">download</field>
</record>

From Python

def action_open_external(self):
    return {
        'type': 'ir.actions.act_url',
        'url': 'https://www.example.com/property/%d' % self.id,
        'target': 'new',
    }

Client Actions (ir.actions.client)

Client actions trigger a handler implemented entirely in JavaScript — the server has no knowledge of what happens after dispatching the action.

Fields

FieldDescription
tagClient-side identifier registered in the actions registry.
paramsOptional Python dict passed to the client handler.
targetcurrent (default), new, fullscreen, or main.

Example

<record id="action_estate_dashboard" model="ir.actions.client">
    <field name="name">Estate Dashboard</field>
    <field name="tag">estate.dashboard</field>
    <field name="target">main</field>
</record>
Register the handler in JavaScript:
/** @odoo-module **/

import { registry } from "@web/core/registry";
import { EstateDashboard } from "./estate_dashboard";

registry.category("actions").add("estate.dashboard", EstateDashboard);

Build docs developers (and LLMs) love