How to dynamically generate selection field values in an Odoo wizard based on contextual data — such as the record from which the wizard is launched.
This is especially useful in cases where a user needs to pick from a filtered list related to the current model, like selecting layouts for a specific dashboard.
1. Define the Wizard Model
Beginning by creating a TransientModel
wizard with a dynamic domain on the layout_select
field. This ensures only related layouts are shown based on the dashboard_id
.
wizard/select_layout.py
from odoo import models, fields, api
class SelectMap(models.TransientModel):
_name = 'dashboard.select.map.wizard'
_description = 'Select Layout Wizard'
dashboard_id = fields.Many2one(
'indoor.dashboard',
string="Dashboard Reference",
required=True
)
layout_select = fields.Many2one(
'indoor.dashboard.layout',
string='Layout'
)
@api.onchange('dashboard_id')
def _onchange_dashboard_id(self):
if self.dashboard_id:
return {
'domain': {
'layout_select': [('dashboard_id', '=', self.dashboard_id.id)]
}
}
2. Create the XML View for the Wizard
Define the form view for our wizard in XML. This layout includes the layout_select
field and two buttons: View and Cancel.
wizard/select_layout.xml
<odoo>
<record id="view_dashboard_select_map_wizard_wizard_form" model="ir.ui.view">
<field name="name">view_dashboard_select_map_wizard_wizard_form</field>
<field name="model">dashboard.select.map.wizard</field>
<field name="arch" type="xml">
<form>
<group>
<field name="layout_select" domain="[('dashboard_id','=', dashboard_id)]" string="Layout" options="{'no_quick_create':True,'no_create_edit':True}" />
<field name="dashboard_id" invisible="1" />
</group>
<footer>
<button string="View" type="object" name="btn_view" class="btn-primary" />
<button string="Cancel" class="btn-secondary" special="cancel" />
</footer>
</form>
</field>
</record>
</odoo>
3. Open the Wizard from the Main Model
Inside main model (indoor.dashboard
), add a method that creates and opens the wizard. This is typically triggered by a button click.
models/indoor_dashboard.py
class IndoorDashboard(models.Model):
_name = 'indoor.dashboard'
_description = 'Indoor Dashboard Management'
name = fields.Char(string='Name', required=True, copy=False, readonly=True,
default=lambda self: self.env['ir.sequence'].next_by_code('indoor.dashboard.sequence') or 'New')
title = fields.Char(string='Title')
layout_ids = fields.One2many('indoor.dashboard.layout', 'dashboard_id', string='Layout')
def btn_view(self):
self.ensure_one()
# Create the wizard with dashboard_id pre-filled
wizard = self.env['dashboard.select.map.wizard'].create({
'dashboard_id': self.id,
})
# Open the wizard with the record ID
return {
'type': 'ir.actions.act_window',
'res_model': 'dashboard.select.map.wizard',
'view_mode': 'form',
'target': 'new',
'res_id': wizard.id,
'context': {
'default_dashboard_id': self.id
}
}
Sample Result
When you click the button, the wizard opens and only shows layouts related to the selected dashboard:
Reply