Skip to content

Action Results

Model methods (button actions, wizard confirmations, etc.) can return action result dictionaries that instruct the frontend how to respond.

Closes the current modal/wizard and optionally reloads the parent view.

return {'type': 'close', 'reload': True}
# With notification
return {
'type': 'close',
'reload': True,
'notify': 'Operation completed successfully'
}
PropertyTypeDescription
reloadboolWhether to reload the parent view
notifystringOptional success message to display

Shows a notification without closing the modal. color controls the toast type (blue info — default, green success, yellow/orange warning, red error).

return {
'type': 'notify',
'message': 'This is an informational message',
'color': 'green',
}

A notification may carry an action — any action dict (e.g. a window_action or url) — which is rendered as a button on the toast that navigates there. Use it to turn a notification into a one-click next step (“Invoice posted → View Invoice”). This is the same mechanism that powers actionable errors (see Exceptions), so notifications of any colour can deep-link, not just errors.

return {
'type': 'notify',
'message': f'Invoice {invoice.number} posted.',
'color': 'green',
'action': {
'type': 'window_action',
'identifier': 'financial_document_customer_invoice_action',
'record_id': invoice.id,
},
'action_label': 'View Invoice', # optional; defaults to the action's label or "Open"
}

Downloads a file to the user’s device. The file content is base64-encoded.

import base64
async def action_export_csv(self):
csv_content = "Name,Email\nJohn,john@example.com"
csv_bytes = csv_content.encode('utf-8')
csv_base64 = base64.b64encode(csv_bytes).decode('utf-8')
return {
'type': 'file_download',
'filename': 'export.csv',
'content': csv_base64,
'mimetype': 'text/csv',
}
PropertyTypeRequiredDescription
filenamestringYesThe download filename
contentstringYesBase64-encoded file content
mimetypestringNoMIME type (defaults to application/octet-stream)

Common MIME types:

  • text/csv - CSV files
  • application/json - JSON files
  • application/pdf - PDF files
  • application/vnd.openxmlformats-officedocument.spreadsheetml.sheet - Excel files
  • text/plain - Plain text files

The modal/wizard stays open after download, allowing users to perform additional actions.

Opens a wizard modal. Used for chaining wizards or opening a wizard from a button action.

return {
'type': 'wizard',
'model': 'CreateInvoiceWizard',
'title': 'Create Invoice',
'ctx': {
'default_contact': self.contact.id,
'active_model': 'SaleOrder',
'active_ids': [self.id],
}
}
PropertyTypeDescription
modelstringThe wizard model name
titlestringOptional modal title
methodstringOptional method name (defaults to action_confirm)
ctxdictContext passed to the wizard

Returns values to update the parent form. Useful for wizards that modify the parent record.

return {
'type': 'update_parent',
'values': {
'discount': 10,
'lines': [('C', {'product': 1, 'qty': 5})],
}
}

Navigates to a record’s form view.

return {
'type': 'window_action',
'action': created_invoice.id,
'model': 'Invoice'
}

Opens the send message modal with optional pre-selected template.

return {
'type': 'send_message',
'template_id': 5, # Optional - pre-select template
'modal_type': 'message' # 'message', 'note', or 'followers'
}
PropertyTypeDescription
modelstringModel name (auto-detected from context)
record_idintRecord ID (auto-detected from context)
template_idintEmailTemplate ID to pre-select
modal_typestringmessage, note, or followers
rendered_subjectstringPre-rendered subject (for transient models without DB records)
rendered_bodystringPre-rendered body HTML (for transient models without DB records)
report_idintReportAction ID to attach as PDF
contactsarrayPre-populated recipients: [{id, name, email}]

Pre-rendered templates: For transient models (wizards with _transient = True), the standard template rendering won’t work because there’s no database record to fetch. Instead, pre-render the template on the backend and pass rendered_subject and rendered_body. See CustomerStatementWizard.action_send_statement() for an example.

Generates and downloads a PDF report.

return {
'type': 'report',
'report_id': report_action.id,
'model': 'Invoice',
'instance_ids': [self.id], # Records to render
}
# Or with computed data (for report wizards)
return {
'type': 'report',
'report_id': report_action.id,
'model': 'ReportWizard',
'report_data': computed_data, # Passed to template
'contact_id': contact_id, # Optional - for customer language formatting
}
PropertyTypeDescription
report_idintReportAction ID
modelstringModel name
instance_idsarrayRecord IDs (record-based reports)
report_dataobjectComputed data dict (wizard-based reports)
contact_idintContact ID for customer-facing date formatting
class Contact(Model):
async def action_export_vcard(self):
"""Export contact as vCard file."""
vcard = f"""BEGIN:VCARD
VERSION:3.0
FN:{self.name}
EMAIL:{self.email}
TEL:{self.phone}
END:VCARD"""
import base64
content = base64.b64encode(vcard.encode('utf-8')).decode('utf-8')
return {
'type': 'file_download',
'filename': f'{self.name}.vcf',
'content': content,
'mimetype': 'text/vcard',
}
class ExportWizard(Model):
_transient = True
format = Selection([
('csv', 'CSV'),
('json', 'JSON'),
], default='csv')
async def action_download(self):
"""Generate and download export file."""
active_ids = self._ctx.get('active_ids', [])
records = await get_model("Contact").filter(id__in=active_ids).all()
if self.format == 'csv':
content = self._generate_csv(records)
mimetype = 'text/csv'
ext = 'csv'
else:
content = self._generate_json(records)
mimetype = 'application/json'
ext = 'json'
import base64
encoded = base64.b64encode(content.encode('utf-8')).decode('utf-8')
return {
'type': 'file_download',
'filename': f'contacts.{ext}',
'content': encoded,
'mimetype': mimetype,
}