How to Implement Field-Level Constraints in Odoo?
✅ What Are They?
Both are used to validate data and enforce business rules in Odoo, but they differ in where and how they work.
Feature | @api.constrains | SQL Constraints (_sql_constraints) |
Type | Python-based ORM constraint | PostgreSQL-level constraint |
Triggered On | create() and write() | Automatically at the DB level |
Can Be Conditional | ✅ Yes | ❌ No (purely structural) |
Supports Complex Logic | ✅ Yes (if/else, cross-field validation) | ❌ No |
User Feedback | ValidationError in Python | DB-level error message |
📌 Realistic Use Case 1: Prevent Duplicate Emails on Customers
Using SQL Constraint
_sql_constraints = [
('email_unique', 'unique(email)', 'Email must be unique.')
]
- Applied at the database level.
- Prevents duplicate values.
- Fast and efficient, but only for simple, single-field rules.
📌 Realistic Use Case 2: Ensure Discount ≤ 50% for Special Products
Using @api.constrains
from odoo.exceptions import ValidationError
@api.constrains('discount', 'product_id')
def _check_discount_limit(self):
for line in self:
if line.product_id.is_special and line.discount > 50:
raise ValidationError("Discount cannot exceed 50% for special products.")
- Triggers when discount or product_id is changed.
- Can use custom logic, conditions, and multiple fields.
- Ideal for business logic validations.
⚙️ When to Use What?
Scenario | Use @api.constrains | Use SQL Constraint |
Cross-field validation | ✅ Yes | ❌ No |
Simple uniqueness or non-null checks | ❌ No | ✅ Yes |
Dynamic rules based on other fields | ✅ Yes | ❌ No |
Performance-critical constraints | ❌ Slower | ✅ Faster |
Needs translatable error messages | ✅ Yes | ✅ Yes |
✅ Summary Table
Criteria | @api.constrains | SQL Constraint (_sql_constraints) |
Level | Application / ORM | Database |
Complex conditions | ✅ Supported | ❌ Not supported |
Cross-field validation | ✅ Yes | ❌ No |
Automatic enforcement | On create/write in ORM | On DB commit |
Error type | ValidationError | DB constraint violation error |
Customizable message | ✅ Yes | ✅ Yes |
✅ Best Practices
- Use SQL constraints for structural validation (e.g., uniqueness).
- Use @api.constrains for business logic validation involving conditions or multiple fields.
- Avoid putting complex logic inside SQL constraints;