Wizard Creation & Management Odoo 18
By Braincuber Team
Published on December 28, 2025
Developer building batch operations creates workflow chaos: user needs to send WhatsApp messages to 50 customers, creates 50-field form showing every single customer field (name/email/phone/address/tax ID/payment terms) overwhelming user with irrelevant data, form modifies permanent customer records causing accidental data overwrites when user types in wrong field, no cancellation option forcing browser back button to exit, and no guided multi-step process—creating user confusion and data integrity risks from complex permanent model forms instead of simple temporary wizard interfaces guiding users through focused single-purpose tasks.
Odoo 18 Wizards enable temporary task-focused interfaces through TransientModel classes (data auto-deleted after action), popup dialog display (target='new' non-disruptive workflow), context pre-population from source records, focused field collection (only relevant inputs), action buttons executing business logic, cancel functionality, and multi-step workflows—separating temporary user input from permanent data models reducing development complexity 60% while improving UX through guided task completion preventing accidental data modification of source records.
Wizard Features: TransientModel (temporary data), Popup dialog, Context passing, Focused fields, Action methods, Cancel option, Multi-step support, Data isolation, Guided workflow
What is Wizard?
Temporary popup interface for focused task completion:
- Transient Data: Not stored permanently, auto-deleted after use
- Popup Dialog: Opens in overlay window, doesn't navigate away from current page
- Task-Focused: Collects only necessary inputs for specific action
- Isolated: Doesn't directly modify source records until action confirmed
Common Wizard Use Cases:
- Data import wizards
- Batch operations (mass email, status updates)
- Configuration wizards (multi-step setup)
- Report generation with parameters
- Record transformation (convert lead to opportunity)
- Communication tasks (send message, create activity)
Wizard Components
Four core components required:
- TransientModel (Python): Defines wizard data structure
- Form View (XML): Defines wizard UI layout
- Action Method (Python): Business logic executed on button click
- Trigger (XML/Python): Button or menu opening wizard
Example: WhatsApp Message Wizard
Complete wizard implementation for sending WhatsApp messages from contact records.
Step 1: Create Transient Model
File: models/whatsapp_send_message.py
from odoo import fields, models
class WhatsappSendMessage(models.TransientModel):
_name = 'whatsapp.send.message'
_description = "Whatsapp Wizard"
user_id = fields.Many2one('res.partner', string="Recipient")
mobile = fields.Char(
related='user_id.mobile',
required=True
)
message = fields.Text(string="Message", required=True)
def action_send_message(self):
"""Send WhatsApp message logic here"""
# Implementation: integrate with WhatsApp API
# Use self.mobile and self.message
passCode Explanation:
- models.TransientModel: Base class for wizards (vs models.Model for permanent data)
- _name: Unique model identifier
- user_id: Many2one to res.partner (customer/contact)
- mobile: Related field auto-filled from selected partner's mobile
- message: Text field for message content
- action_send_message: Method called when Send button clicked
Step 2: Add Button to Contact Form
File: views/res_partner_views.xml
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_partner_form" model="ir.ui.view">
<field name="name">res.partner.view.form.inherit.whatsapp</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<!-- Add WhatsApp button to partner form -->
<xpath expr="//div[@name='button_box']" position="inside">
<div class="oe_button_box" name="button_box">
<button name="action_send_msg"
string="Whatsapp"
type="object"
class="oe_stat_button"
icon="fa-whatsapp"/>
</div>
</xpath>
</field>
</record>
</odoo>XML Explanation:
- inherit_id: References base contact form view
- xpath: Locates button_box section for button insertion
- name="action_send_msg": Python method called on click
- type="object": Calls Python method (vs type="action")
- icon="fa-whatsapp": FontAwesome icon
Step 3: Create Action Method
File: models/res_partner.py
from odoo import models, _
class ResPartner(models.Model):
_inherit = 'res.partner'
def action_send_msg(self):
"""Opens wizard to send WhatsApp message"""
return {
'type': 'ir.actions.act_window',
'name': _('Whatsapp Message'),
'res_model': 'whatsapp.send.message',
'target': 'new',
'view_mode': 'form',
'view_type': 'form',
'context': {'default_user_id': self.id},
}Action Dictionary Explanation:
| Key | Purpose |
|---|---|
| type | Defines action type (act_window = open window) |
| name | Window title displayed to user |
| res_model | Wizard model to open |
| target | 'new' = popup dialog, 'current' = same window |
| view_mode | Display mode (form/tree/kanban) |
| context | Pass data to wizard (default_user_id = current contact) |
Step 4: Create Wizard View
File: views/whatsapp_send_message_views.xml
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- Wizard Form View -->
<record id="whatsapp_send_message_view_form" model="ir.ui.view">
<field name="name">whatsapp.send.message.view.form</field>
<field name="model">whatsapp.send.message</field>
<field name="priority" eval="8"/>
<field name="arch" type="xml">
<form string="Whatsapp Message">
<group>
<field name="user_id"/>
<field name="mobile"/>
</group>
<group>
<field name="message"/>
</group>
<footer>
<button name="action_send_message"
string="Send"
type="object"/>
<button name="cancel"
string="Cancel"
special="cancel"/>
</footer>
</form>
</field>
</record>
</odoo>View Structure:
- <group>: Organizes fields in columns
- <field>: Displays wizard fields (user_id, mobile, message)
- <footer>: Action buttons area
- type="object": Send button calls action_send_message method
- special="cancel": Cancel button closes wizard without action
Complete Workflow
- User opens contact record (res.partner)
- User sees WhatsApp button in button_box
- User clicks WhatsApp button
- action_send_msg method called
- Returns action dictionary opening wizard
- Wizard popup appears with form
- user_id pre-filled from context (default_user_id)
- mobile auto-filled from selected partner
- User types message text
- User clicks Send button
- action_send_message method executes
- WhatsApp API integration sends message
- Wizard closes automatically
- User back to contact form
Context Pre-Population
Pass data from source record to wizard:
'context': {
'default_user_id': self.id,
'default_message': 'Hello from our company!',
}default_[field_name]: Automatically fills wizard field with provided value
Example: Opens wizard with recipient and pre-filled greeting message
Multi-Step Wizards
Create wizards with multiple pages:
Implementation Pattern:
- Add state field to track current step:
state = fields.Selection([ ('step1', 'Configuration'), ('step2', 'Preview'), ('step3', 'Confirmation') ], default='step1') - Use attrs to show/hide fields per step
- Create next_step methods updating state
- Final step calls actual action method
Best Practices
Always Use TransientModel for Wizards: Using models.Model instead of models.TransientModel = permanent database storage. Wizard data accumulates forever causing database bloat. 1000 wizard uses = 1000 permanent records never deleted. TransientModel auto-deletes after completion keeping database clean.
Include Cancel Button Always: Wizard without cancel button = user stuck forcing browser back button or page refresh. Confusing UX frustrating users. Always include: <button special="cancel"/> providing clean exit path.
Pre-Populate Fields via Context: Empty wizard forcing user to re-select current record = terrible UX. Context pre-population: wizard opens already knowing contact = user just fills message not re-entering recipient. Saves 3+ clicks per use improving efficiency 60%.
Common Wizard Patterns
1. Data Import Wizard:
file = fields.Binary(string="File")
filename = fields.Char()
def action_import(self):
# Parse file, create records2. Mass Update Wizard:
new_status = fields.Selection([...])
def action_mass_update(self):
active_ids = self.env.context.get('active_ids')
records = self.env['model.name'].browse(active_ids)
records.write({'status': self.new_status})3. Report Generation Wizard:
date_from = fields.Date()
date_to = fields.Date()
format = fields.Selection([('pdf', 'PDF'), ('xlsx', 'Excel')])
def action_generate_report(self):
return self.env.ref('module.report_action').report_action(self)Conclusion
Odoo 18 Wizards enable temporary task-focused interfaces through TransientModel classes, popup dialogs, context pre-population, and focused field collection. Reduce development complexity 60% while improving UX through guided workflows separating temporary input from permanent data preventing accidental modifications and database bloat through automatic data cleanup after task completion.
