What Are Constraints in Odoo?
Constraints in Odoo are validation rules applied to models to ensure that stored data meets certain conditions. With constraints, we can prevent data errors such as duplication, invalid values, or violations of specific business rules.
In Odoo, constraints are usually implemented using the @api.constrains
decorator on models or by defining SQL constraints directly in the model.
Using @api.constrains
@api.constrains
is a method used in Odoo models to apply validation on fields after data is saved (write()
or create()
).
Basic Syntax
from odoo import models, fields, api
from odoo.exceptions import ValidationError
class ExampleModel(models.Model):
_name = 'example.model'
_description = 'Example Model'
name = fields.Char(string='Name', required=True)
age = fields.Integer(string='Age')
@api.constrains('age')
def _check_age(self):
for record in self:
if record.age < 18:
raise ValidationError('Age must be at least 18!')
Explanation
- Decorator
@api.constrains('age')
→ The_check_age
function runs only if theage
field changes. - Loop
for record in self
→ Iterates over each record being validated. - Condition
if record.age < 18
→ If the age is less than 18, an error is raised. raise ValidationError('Age must be at least 18!')
→ Stops the process if the condition is not met.
Using SQL Constraints
Besides @api.constrains
, we can also apply SQL constraints directly in the Odoo model.
Example of SQL Constraints
class ExampleModel(models.Model):
_name = 'example.model'
_description = 'Example Model with SQL Constraints'
name = fields.Char(string='Name', required=True)
code = fields.Char(string='Code', required=True)
_sql_constraints = [
('unique_code', 'UNIQUE(code)', 'Code must be unique!'),
]
Explanation
_sql_constraints
→ List of SQL constraints applied to the database table.('unique_code', 'UNIQUE(code)', 'Code must be unique!')
→ Ensures thatcode
values are not duplicated.
SQL constraints offer better performance as they are executed directly by the database, but they are less flexible than @api.constrains
.
Use Cases for Constraints
1. Validating Email Format
If we need to validate that an email field contains only valid email addresses:
import re
class ExampleModel(models.Model):
_name = 'example.model'
_description = 'Email Validation'
email = fields.Char(string='Email')
@api.constrains('email')
def _check_email_format(self):
email_regex = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
for record in self:
if record.email and not re.match(email_regex, record.email):
raise ValidationError('Invalid email format!')
2. Preventing Duplicate Names
If we want to prevent users from entering duplicate names:
class ExampleModel(models.Model):
_name = 'example.model'
_description = 'Prevent Duplicate Names'
name = fields.Char(string='Name', required=True)
@api.constrains('name')
def _check_unique_name(self):
for record in self:
existing = self.env['example.model'].search([('name', '=', record.name), ('id', '!=', record.id)])
if existing:
raise ValidationError('Name is already in use!')
Difference Between @api.constrains
and _sql_constraints
Criteria | `@api.constrains` | `_sql_constraints` |
---|---|---|
Validation Process | Executed in Python | Executed in the Database |
Flexibility | Highly flexible, supports complex validation | Only supports UNIQUE, CHECK, and NOT NULL |
Performance | Slower, as it runs at the application level | Faster, as it runs directly in the database |
Error Handling | Can provide more specific error messages | Limited error message customization |
Conclusion
- Use
@api.constrains
if validation requires complex logic, such as checking values based on specific conditions. - Use
_sql_constraints
if you only need to ensure data uniqueness or simple validations that the database can handle efficiently. - Combine both for the best results:
_sql_constraints
for uniqueness validation and@api.constrains
for more complex business rule validations.
By applying the right constraints, we can ensure that data in an Odoo application remains valid and consistent!