In Odoo development, domains are essential for filtering and controlling which records users can see and select within relational fields. Whether you're building modules for Sales, HR, Inventory, or custom applications, domains help ensure that only relevant data appears based on specific conditions. In Odoo 19, domain handling in views has become more flexible and powerful, especially when combined with computed fields, context values, and onchange methods. By implementing dynamic domains, developers can create smarter, more responsive forms that adapt automatically to user input and business logic. In this blog, we’ll explore what domains are, what makes them dynamic, the different ways to implement them in Odoo 19, real-world examples, best practices, and frequently asked questions.
What is a Domain in Odoo?
A domain in Odoo is a list of conditions used to filter records in relational fields, like:
- Many2one
- One2many
- Many2many
Example:
<field name="partner_id" domain="[('customer_rank', '>', 0)]"/>This filters only customer records.
What is a Dynamic Domain?
A dynamic domain in Odoo is a domain that changes automatically based on certain conditions rather than using fixed, hardcoded values. It can adapt according to another field’s value in the form, the currently logged-in user, context values passed from the view or action, computed logic defined in the backend, the active company in a multi-company environment, or even date-based conditions. Instead of remaining static, a dynamic domain reacts intelligently to user input or backend logic, ensuring that only relevant and context-specific records are displayed.
Methods to Apply Dynamic Domains in Odoo 19
Dynamic Domain Using Another Field in XML
This is the most common method.
Example Scenario:
Filter products based on selected category.
Python:
class SaleOrder(models.Model):
_inherit = "sale.order"
product_category_id = fields.Many2one('product.category')
product_id = fields.Many2one('product.product')
XML:
<field name="product_category_id"/>
<field name="product_id"
domain="[('categ_id', '=', product_category_id)]"/>
How It Works
When product_category_id changes, product_id gets filtered automatically.
Dynamic Domain Using Onchange Method
When filtering logic depends on multiple fields or requires backend calculations, the @api.onchange method can still be used to dynamically adjust field values. Instead of returning a domain directly, it is recommended to update related fields or helper fields that control the domain in the view.
Python:
from odoo import models, fields, api
class SaleOrder(models.Model):
_inherit = "sale.order"
product_category_id = fields.Many2one('product.category')
product_id = fields.Many2one('product.product')
allowed_product_ids = fields.Many2many('product.product')
@api.onchange('product_category_id')
def _onchange_product_category(self):
if self.product_category_id:
products = self.env['product.product'].search([
('categ_id', '=', self.product_category_id.id)
])
self.allowed_product_ids = products
else:
self.allowed_product_ids = False
XML
<field name="product_category_id"/>
<field name="product_id"
domain="[('id', 'in', allowed_product_ids)]"/>
How It Works
When the product_category_id changes, the onchange method updates allowed_product_ids. The domain on product_id then filters the selectable products using those IDs. This approach is more reliable and compatible with modern Odoo versions.
Dynamic Domain Using Context
You can pass values via context.
XML:
<field name="product_id"
context="{'default_categ_id': product_category_id}"
domain="[('categ_id', '=', context.get('default_categ_id'))]"/>
Context-based domains are useful in popup forms and wizards.
Dynamic Domain Based on Logged-in User
Python:
user_id = fields.Many2one(
'res.users',
default=lambda self: self.env.user,
)
XML:
<field name="employee_id"
domain="[('user_id', '=', uid)]"/>
Here, uid represents the logged-in user.
Dynamic Domain Using Computed Helper Field
When logic becomes complex, use a computed Many2many helper field.
Python:
allowed_product_ids = fields.Many2many(
'product.product',
compute='_compute_allowed_products'
)
def _compute_allowed_products(self):
for rec in self:
rec.allowed_product_ids = self.env['product.product'].search([
('sale_ok', '=', True)
])
XML:
<field name="product_id"
domain="[('id', 'in', allowed_product_ids)]"/>
This approach is clean and scalable.
Best Practices for Dynamic Domains
- Keep XML domains simple
- Avoid heavy searches inside onchange
- Use computed helper fields for scalability
- Always test with multiple users
- Consider record rules when security is involved
Dynamic domains in Odoo 19 allow developers to build intelligent and user-friendly forms. By combining XML, context, onchange methods, and computed fields, you can create powerful filtering mechanisms tailored to business needs.
Mastering dynamic domains significantly improves user experience and data accuracy in your Odoo applications.
To read more about How to Apply Dynamic Domain for Relational Fields in Odoo 19, refer to our blog How to Apply Dynamic Domain for Relational Fields in Odoo 19.