Python Dialog API (frappe.ui.py_dialog) in Frappe v15
What is a Python Dialog in Frappe?
frappe.ui.py_dialog is a server-side API that allows Python code to render and control UI dialogs dynamically in the Desk.
It is used to show interactive popups with form fields, custom UI actions, and callback logic directly from backend logic.
Unlike the JavaScript Dialog API, the Python Dialog allows the server to display UI dialogs triggered by server events, such as:
- DocType events (validate, before_save)
- Custom server scripts
- Background job interaction
- Server actions in workflow
When Should You Use the Python Dialog API?
Use frappe.ui.py_dialog when:
- The dialog should open from server-side execution
- Data validation requires user input
- You want a modal UI flow controlled by Python
- You need user confirmation before saving
- Dynamic UI needs backend computation
It is not intended for normal form rendering.
For client-side UI, use frappe.ui.Dialog (JS).
How to Create a Python Dialog in Frappe v15
Basic Example
import frappe
from frappe.ui.py_dialog import Dialog
def show_dialog():
dialog = Dialog(
title="Confirm Action",
fields=[
{"label": "Reason", "fieldname": "reason", "fieldtype": "Small Text"},
],
primary_action_label="Submit",
primary_action=on_submit
)
dialog.show()
def on_submit(values):
frappe.msgprint(f"You entered: {values.reason}")
How it Works
- Dialog class defines UI
- show() renders dialog on the user’s screen
- primary_action(values) receives user input
Python Dialog Constructor
Dialog Structure
Dialog(
title: str,
fields: list,
primary_action_label: str,
primary_action: callable,
size: str = "small",
secondary_action_label: str = None,
secondary_action: callable = None
)
Parameters
| Parameter | Type | Description |
| title | string | Dialog header title |
| fields | list | List of field definitions |
| primary_action_label | string | Button label |
| primary_action | function | Callback executed on primary button click |
| size | string | Dialog size (small, large, extra-large) |
| secondary_action_label | string | Optional secondary action label |
| secondary_action | function | Secondary callback |
Supported Field Types
The dialog supports all standard Frappe field types:
Examples:
- Data
- Small Text
- Select
- Link
- Date
- Int
- Float
- Check
- Table (Inline Table)
- Column Break
- Section Break
Example field definition:
{
"label": "Customer",
"fieldname": "customer",
"fieldtype": "Link",
"options": "Customer",
"reqd": 1
}
Full Example with Multiple Fields
import frappe
from frappe.ui.py_dialog import Dialog
def dialog_example():
dialog = Dialog(
title="Create Meeting",
fields=[
{"label": "Subject", "fieldname": "subject", "fieldtype": "Data", "reqd": 1},
{"label": "Date", "fieldname": "date", "fieldtype": "Date"},
{"label": "Participants", "fieldname": "participants", "fieldtype": "Table", "options": "Meeting Participant"},
],
primary_action_label="Create",
primary_action=create_meeting
)
dialog.show()
def create_meeting(values):
meeting = frappe.get_doc({
"doctype": "Meeting",
"subject": values.subject,
"date": values.date,
})
meeting.insert()
frappe.msgprint("Meeting Created")
Dialog Actions & Event Handling
Primary Action Callback
Action executed after clicking the main action button.
def on_submit(values):
frappe.msgprint(values.get("reason"))
The values argument is a dictionary mapping fieldname → value.
Secondary Action Example
Dialog(
...,
secondary_action_label="Cancel",
secondary_action=lambda values: frappe.msgprint("Cancelled")
)
Showing Dialog from DocType Events
Python dialogs can be invoked from document events:
Example in DocType Controller
def validate(self):
if not self.approved:
from frappe.ui.py_dialog import Dialog
dialog = Dialog(
title="Approval Required",
fields=[
{"label": "Approver Comments", "fieldname": "remarks", "fieldtype": "Small Text"}
],
primary_action_label="Approve",
primary_action=self.on_approve
)
dialog.show()
Rendering Options
Set Dialog Size
Dialog(size="large")
Values:
- small (default)
- large
- extra-large
Return Values and Data Binding
The dialog returns all field values in a Python dictionary:
{
"subject": "Weekly Sync",
"date": "2025-12-08",
"participants": [...]
}
You can use returned data to create records or perform logic.
Best Practices
Recommended Usage
- Use Python dialog only when UI must originate from the backend.
- Keep dialogs small and focused.
- Use JavaScript dialogs for rich UI flows.
- Avoid heavy computation inside action callback.
- Validate data inside callback.
Avoid
- Complex layouts in Python dialogs.
- Large tables inside dialogs.
- Long-running tasks (use background jobs).
- Excessive dialog creation inside loops.
Troubleshooting
Dialog Not Showing
- Ensure method is called from a Desk context.
- Python dialog does not work in REST API.
- Import path must be correct:
from frappe.ui.py_dialog import Dialog
Missing Input Data
- Check fieldname spelling.
- Use values.get(“fieldname”).
Cross-References
For related topics:
- JavaScript Dialog (frappe.ui.Dialog)
- Python Response API
- Server Script
- REST API
- Form Events (validate, before_save)
- Background Jobs
- Permissions in Dialog Actions
- Dynamic Link Fields