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;