Overview
In Odoo development, dynamic domains are essential for creating smart, user-friendly forms. They allow you to filter selectable records dynamically based on other field values—preventing wrong data input and improving user experience.
This article explains how dynamic domains work in Odoo, when to use them, and how to implement them correctly for Many2one and Many2many fields using Python and XML, across modern Odoo versions (15–18).
What Is a Domain in Odoo?
A domain is a filter expression used by Odoo to limit records displayed in relational fields.
Example (static domain):
<field name="partner_id" domain="[('is_company', '=', True)]"/>
This works, but it’s static.
Dynamic domains go further by changing automatically based on user input.
Why Use Dynamic Domains?
Dynamic domains help you:
- Prevent invalid data selection
- Reduce user mistakes
- Improve performance by limiting data
- Make forms smarter and more contextual
Common use cases:
- Filter products by category
- Filter partners by company or subcontractor
- Filter employees by department
- Filter locations by warehouse
Dynamic Domain Using @api.onchange (Most Common)
Many2one Example
Scenario:
Filter partner_id based on selected subcon_id.
Python Code
@api.onchange('subcon_id')
def _onchange_subcon_id(self):
if self.subcon_id:
return {
'domain': {
'partner_id': [('id', 'in', self.subcon_id.partner_ids.ids)]
}
}
else:
return {
'domain': {
'partner_id': []
}
}
Why This Works
- Domain updates immediately when subcon_id changes
- No page reload required
- Simple and reliable
Dynamic Domain for Many2many Fields
Scenario
Filter employee_ids based on selected department_id.
Python Code
@api.onchange('department_id')
def _onchange_department_id(self):
if self.department_id:
return {
'domain': {
'employee_ids': [
('department_id', '=', self.department_id.id)
]
}
}
Notes
- Domain applies to selection popup
- Works well for large datasets
- Avoid heavy logic inside onchange
Dynamic Domain Directly in XML
You can also define dynamic domains using field values in XML.
Example
<field name="partner_id"
domain="[('company_id', '=', company_id)]"/>
When to Use XML Domains
- Simple field dependency
- No complex Python logic needed
- Cleaner and faster
Limitation
- Cannot use Python logic
- Limited to field values available in the view
Using domainField Attribute in Python (Advanced)
Sometimes you want the domain to be fully dynamic and reusable.
Example
partner_id = fields.Many2one(
'res.partner',
domain="[('is_company', '=', True)]"
)
⚠️ This domain is evaluated client-side, not server-side.
Common Mistakes (And How to Avoid Them)
❌ Using self incorrectly in onchange
('id', 'in', self.subcon_id.partner_ids)
✅ Correct:
('id', 'in', self.subcon_id.partner_ids.ids)
❌ Forgetting to reset field value
When a domain changes, old values might become invalid.
✅ Best Practice:
self.partner_id = False
❌ Overloading onchange logic
Avoid heavy loops or database searches inside onchange.
Dynamic Domain vs Record Rules
| Feature | Dynamic Domain | Record Rule |
|---|---|---|
UI Filtering | ✅ Yes | ❌ No |
Security | ❌ No | ✅ Yes |
User-specific | ⚠️ Limited | ✅ Yes |
Performance | Fast | Medium |
👉 Use domains for UX, record rules for security.
Debugging Dynamic Domains
Tips
- Enable developer mode
- Inspect field domain in browser
- Log domain output temporarily
- Test with different users
Quick Debug
import logging
_logger = logging.getLogger(__name__)
_logger.info("Domain applied: %s", domain)
Best Practices Summary
✅ Use XML domains for simple dependencies
✅ Use @api.onchange for dynamic logic
✅ Always reset dependent fields
✅ Avoid heavy computation in onchange
✅ Never rely on domains for security
Conclusion
Dynamic domains are one of the most powerful tools in Odoo form customization. When used correctly, they make your application smarter, safer, and more user-friendly—without complex JavaScript or custom widgets.
Mastering dynamic domains for Many2one and Many2many fields will significantly improve the quality of your Odoo modules.
