Overview of Method Decorators in Odoo 16

August 21, 2023

Method decorators are used to modify the function, it extends the characteristics and behavior of the function. Functions defined in Odoo/api.py, which can be used with the other functions. For using method decorators, we should import API from Odoo.

from odoo import models, fields, api

The decorators in Odoo include the following:
API. model
@api.model might be used to link a particular function with a specific data model. When we are trying to create a record/data in Odoo, this decorator is used to send the data to the API.

Example code for @api.model:


def create(self, vals):

"""To create reference number"""

if vals.get('sequence', ('New')) == ('New'): vals['sequence'] = self.env['ir.sequence'].next_by_code(

'service.charge') or _('New')

result = super(ServiceCharge, self).create(vals) return result

The desired output:


The model_create_multi decorators are used with the methods developed to facilitate the creation of multiple records of a specific model in Odoo, streamlining the process and potentially improving performance.

Example code for @api.model_create_multi:

def create(self, vals_list): for data in vals_list:
if 'odometer' in data and not data['odometer']:
# if received value for odometer is 0, then remove it from the # data as it would result to the creation of a
# odometer log with 0, which is to be avoided del data['odometer']
return super(FleetVehicleLogServices, self).create(vals_list)


API. on change
@api.onchange decorator is to define “on-change” methods. These methods are invoked automatically when a specified field’s value changes in a form view. They allow developers to perform computations, update other fields, or trigger actions based on the changes made by the user in the form. The change decorator supports simple field names only, and it does not support dotted names(fields of relational fields like product_id.name). It is not possible to modify one2many and many2many fields.

Example code for @api.onchange:

@api.onchange('invoice_id') def _onchange_invoice(self):

product = self.invoice_id.invoice_line_ids storable_product = [rec.product_id.id for rec in product

if rec.product_id.detailed_type == 'product'] return {'domain': {'product_id': [('id', 'in', storable_product)]}}

The desired output:

This decorator is used to specify the compute dependencies for a computing method. Each argument should be a string of field names, wherein it is able to be a clean or a dot-separated collection of field names.

Example code for @api.depends:

@api.depends('unit_price') def _compute_charge(self):

for rec in self:

rec.service_charge = 0.1 * rec.unit_price

The desired output:


We use the decorator for non-stored ‘compute’ methods to indicate the context dependencies for these methods. The arguments passed will be the key in the context’s dictionary.

Example code for @api.depends_context:

@api.depends_context('company') def _compute_currency_id(self):

self.currency_id = self.env.company.currency_id

The ondelete decorator will trigger when unlinking the records. This is used to prevent the deletion of validated records. The methods with ondelete decorators check for some conditions specified in them and raise an error based on the result.


at_uninstall (bool): Whether the decorated method should be called if the module is being uninstalled. If False, the module uninstallation does not trigger those errors.

Example code for @api.ondelete:

@api.ondelete(at_uninstall=False) def _unlink_if_state_draft(self):

if self.state == 'done':

raise UserError("Can't delete an confirmed service order!")

same as above but with unlink_except * as method name def _unlink_except_state_done(self):

if self.state == 'done':

raise UserError("Can't delete an confirmed service order!")

The desired output:


All the strategies described with the autovacuum approach decorator may be invoked via way of means of the day-by-day vacuum cron process described with the version ir.autovacuum. It can be used to define the garbage-collection-like methods that are run at least daily.

Example code for @api.autovaccum:


def _archive_meeting_rooms(self):

self.sudo().search([ ("is_pinned", "=", False),

("active", "=", True), ("room_participant_count", "=", 0),

("room_last_activity", "<", fields.Datetime.now() - self._DELAY_CLEAN),

]).active = False


The constraints decorator is used to define constraints on a model’s fields. Constraints are rules or conditions that must be satisfied to maintain data integrity and consistency in the database. When a record is created or updated, the constraints defined with @api.constrains are checked to ensure that the data meets the specified conditions. If any of the constraints fail, the system will raise an exception, and the operation to create or update the record will be rejected.

Example code for @api.constrains:

@api.constrains('service_cost') def check_total_cost(self):

if self.service_cost >= self.unit_price:

raise ValidationError('service cost is greater than product actual


The desired output:

By using this decorator, we can return anything we want from a specific function. It adapts a technique output to the api fashion: id , ids, or fake for conventional fashion and record set for the document.


model – a string that can be either ‘self’ for the current model or a model name like ‘res.partner’.

downgrade – a function that converts the record-style value to a traditional-style output. downgrade(self, value, *args, **kwargs)

The arguments self, *args, and **kwargs of the downgrade or upgrade function parameters are the same, which are passed to the method in the record-style.

@api.returns('self', lambda value: value.id) def copy(self, default=None):

order = super(SaleOrder, self).copy(default)

reward_lines = order.order_line.filtered('is_reward_line') if reward_lines:

reward_lines.unlink() return order
Request Your Free Quote

"Unlock the Full Potential of Your Business with Odoo ERP!"

"Get a Cost Estimate for Your ERP Project, Absolutely FREE!"

Get a Free Quote

Leave a Reply

Your email address will not be published. Required fields are marked *