Method decorators in Odoo 18 play a critical role in altering or extending the behavior of existing methods without modifying their actual implementation. These decorators wrap methods and provide additional functionality, streamlining operations and enhancing the flexibility of the Odoo framework. Understanding how and when to use these decorators can significantly improve your development workflow, especially when building complex enterprise applications.
Here’s a closer look at some key method decorators in Odoo 18 and how they are typically used.
1. @api.model : This decorator is used for methods that do not depend on any specific record. It means the method can be called without needing a particular recordset and operates in the context of the model, rather than on individual records.
Example:
from odoo import models, api
class CustomModel(models.Model):
_name = 'custom.model'
@api.model
def my_model_method(self):
# code that does not rely on a particular record
return "This method can be called without records"
In this case, my_model_method is accessible from the model level and can handle logic without any specific record context.
2. @api.depends: The @api.depends decorator is crucial for computed fields. It specifies the fields that a computed method depends on, ensuring that the method is triggered to recalculate when any of these dependent fields are changed.
Example:
class CustomModel(models.Model):
_name = 'custom.model'
my_field = fields.Integer(compute='_compute_my_field')
@api.depends('other_field')
def _compute_my_field(self):
for record in self:
record.my_field = record.other_field * 2
In this example, _compute_my_field will be recalculated whenever the value of other_field changes.
3. @api.constrains: This decorator is used to enforce constraints on field values. When the specified fields are changed, the decorated method will be triggered to check if the values adhere to the defined rules.
Example:
class CustomModel(models.Model):
_name = 'custom.model'
price = fields.Float()
quantity = fields.Integer()
@api.constrains('price', 'quantity')
def _check_price_quantity(self):
for record in self:
if record.price < 0 or record.quantity < 0:
raise ValidationError("Price and quantity must be positive.")
Here, _check_price_quantity ensures that both the price and quantity fields cannot have negative values, and if they do, an exception is raised.
4. @api.onchange: This decorator is used for methods that should be triggered when a specified field is changed in the UI. It’s often utilized in form views to dynamically update fields based on user input before saving the record.
Example:
class CustomModel(models.Model):
_name = 'custom.model'
price = fields.Float()
discount = fields.Float()
@api.onchange('discount')
def _onchange_discount(self):
if self.discount:
self.price = self.price - (self.price * (self.discount / 100))
In this case, _onchange_discount will be called every time the discount field changes and the price will be updated accordingly.
5. @api.returns: The @api.returns decorator for methods that return instances of a specified model. It takes three parameters: model, which is the name of the model or 'self' for the current model; downgrade, a function that converts record-style output to traditional output; and upgrade, a function that converts traditional output to record-style output. The decorator adjusts the method output based on the call style, allowing it to return an ID, a list of IDs, or a recordset.
Example:
class CustomModel(models.Model):
_name = 'custom.model'
@api.returns('self')
def copy(self, default=None):
# Custom logic for copying a record
return super(CustomModel, self).copy(default)
In this example, the method copy ensures that it returns a new instance of the current model's recordset after performing its operation.
6. @api.model_create_multi: This decorator is used when creating multiple records at once. It optimizes performance by minimizing the number of database transactions required.
Example:
class CustomModel(models.Model):
_name = 'custom.model'
@api.model_create_multi
def create(self, vals_list):
# Optimized creation of multiple records
return super(CustomModel, self).create(vals_list)
By using @api.model_create_multi, the method allows creating multiple records efficiently by processing them in batches.
7. @api.autovacuum: The autovacuum method decorator allows you to mark a method so that it runs as part of the daily vacuum cron job (model ir.autovacuum). This is useful for tasks similar to garbage collection, which help manage resources but don’t require a separate cron job. By using this decorator, you can ensure that necessary maintenance tasks are performed automatically on a regular basis without needing to set up individual cron jobs for each task.
8. @api.depends_context: The depends_context decorator specifies which context keys a non-stored "compute" method depends on. Each argument represents a key in the context dictionary. For example,
from odoo import models, fields, api
class ProductTemplate(models.Model):
_inherit = 'product.template'
discount_price = fields.Float(compute='_compute_discount_price')
@api.depends_context('discount_rate')
def _compute_discount_price(self):
for product in self:
discount_rate = self.env.context.get('discount_rate', 0.0)
product.discount_price = product.list_price * (1 - discount_rate / 100)
In this example, the discount_price field computes the discounted price of a product based on the discount_rate key from the context. If the discount_rate is provided in the context, the method calculates the discounted price by applying the rate to the product’s list price. If no discount rate is present, it defaults to zero, resulting in the full list price.
Method decorators in Odoo 18 are powerful tools that enhance the framework's capabilities. They allow developers to create clean, efficient, and reusable code, streamlining the development process. Understanding how to use these decorators effectively can significantly improve your Odoo applications, making them more robust and user-friendly.
Whether you’re creating new models or enhancing existing ones, leveraging method decorators will help you take full advantage of Odoo's powerful features, allowing you to build better solutions for your business needs.
To read more about An Overview of Method Decorators in Odoo 17, refer to our blog An Overview of Method Decorators in Odoo 17.