What is a Function Decorator?

A function decorator in Python is a higher-order function that wraps another function to extend or modify its behavior without permanently changing it.

Decorators are widely used in Odoo to control function execution, permissions, caching, environment checks, etc.


✅ Basic Syntax

@decorator_name

def function_name():

    pass

This is equivalent to:

def function_name():

    pass


function_name = decorator_name(function_name)


✅ Common Built-in Decorators in Python


Decorator

Purpose

@staticmethod

Defines a method that doesn't use self or cls

@classmethod

Passes cls instead of self

@property

Access method like an attribute



📌 Realistic Odoo Examples


1. @api.model

Use when the method does not depend on a recordset (self is a model, not a recordset).​


from odoo import models, api

class ResPartner(models.Model):

    _inherit = 'res.partner'

    @api.model

    def create_default_partner(self):

        return self.create({'name': 'Default Partner'})

self refers to the model, not a record.


2. @api.depends

Used for computed fields. Marks which fields trigger recomputation.​


from odoo import fields, api


total = fields.Float(compute='_compute_total')


@api.depends('amount', 'tax')

def _compute_total(self):

    for rec in self:

        rec.total = rec.amount + rec.tax


3. @api.constrains

Used to define SQL-like constraints at the model level.


@api.constrains('price')

def _check_price(self):

    for rec in self:

        if rec.price < 0:

            raise ValidationError("Price cannot be negative.")


4. @api.onchange

Triggers when a field is modified in the form view.​


@api.onchange('category_id')

def _onchange_category_id(self):

    if self.category_id:

        self.name = self.category_id.name + ' Product'



✅ Custom Decorator Example (Advanced)

You can even define your own decorators:


def log_method(func):

    def wrapper(*args, **kwargs):

        _logger.info("Calling: %s", func.__name__)

        return func(*args, **kwargs)

    return wrapper

class MyModel(models.Model):

    _name = 'my.model'

    @log_method

    def custom_action(self):

        pass




✅ Summary Table


Decorator

Purpose

Usage Example

@api.model

Model-level methods

Create or search methods

@api.depends

Trigger recompute for computed fields

Compute methods

@api.constrains

Data validation

Field-level logic

@api.onchange

UI-triggered updates

Dynamic form behavior