In several cases, we may need to apply a domain for a relational field based on some other field in the same model. In those cases, we can not apply static domains to filter the records based on the comodel fields only. This blog will help you learn some of the different methods to apply domain dynamically.
Take a look at this example:
class EmployeeWing(models.Model):
_name = 'employee.wing'
_description = 'Employee Wing'
department_id = fields.Many2one('hr.department', string='Department')
responsible_person_id = fields.Many2one('hr.employee', related='department_id.manager_id')
pick_from_dept = fields.Boolean('Dept Members Only')
member_ids = fields.Many2many('hr.employee', string='Members')
leader_id = fields.Many2one('hr.employee')
alternate_id = fields.Many2one('hr.employee')
And the form view is defined as:
<record id="wing_form_view" model="ir.ui.view">
<field name="name">employee.wing.form</field>
<field name="model">employee.wing</field>
<field name="arch" type="xml">
<form>
<sheet>`
<group>
<field name="department_id"/>
<field name="responsible_person_id"/>
<field name="pick_from_dept"/>
<field name="member_ids" widget="many2many_tags"/>
<field name="leader_id"/>
<field name="alternate_id"/>
</group>
</sheet>
</form>
</field>
</record>
1. By defining an onchange function to return the domain.
In the given example, suppose we need to apply a filter for the members based on the “Department Members Only” field, ie, if “Department Members Only” is True, then the “Members” field should only allow the employees from the selected department, and if “Department Members Only” is False, then all employees should be available to pick from. Here we can use the onchange function to return the domain. In the python file, we can define the function like this:
@api.onchange('pick_from_dept')
def get_employees(self):
if self.pick_from_dept is True:
domain = [('department_id', '=', self.department_id.id)]
else:
domain = []
return {'domain': {'member_ids': domain}}
2. By defining domain attributes based on the field,
Now we choose a leader from the members selected in the many2many field. Here also, we can use the onchange function to return the domain. But we can do it simply by defining the domain attribute for the field in the XML file like this:
<field name="leader_id" domain="[('id', 'in', member_ids)]"/>
3. By computing the possible values to a many2many field and applying the domain based on that field
Here, we have a related field for the responsible person - the manager of the department. Suppose we need an alternate person for the responsible person, which can be either the manager or the coach of the responsible person.
So for applying this domain, we can not use the onchange function as the responsible person field is not an editable field in the form. Here we can compute the possible values to a many2many field and apply a domain based on that field.
In the python file:
alternate_ids = fields.Many2many('hr.employee', 'wing_alternate_rel',
compute='compute_alternate_ids')
@api.depends('responsible_id')
def compute_alternate_ids(self):
for rec in self:
rec.alternate_ids = False
if rec.responsible_person_id:
if rec.responsible_person_id.parent_id and rec.responsible_person_id.coach_id:
rec.alternate_ids = (rec.responsible_person_id.parent_id.id, rec.responsible_person_id.coach_id.id)
And in the xml:
<field name="alternate_id" domain="[('id', 'in', alternate_ids)]"/>
<field name="alternate_ids" invisible="1"/>
In all the above cases, we have applied a domain to a relational field based on another relational field, ie, the domain for the second is dynamically updated based on the selection made in the first.