How to Create a Custom Server-Side Method for Calendar Views in Frappe
Calendar View MethodLearn to implement a whitelisted Python method in Frappe to fetch dynamic data for Calendar and Gantt views using frappe.db.sql and JSON filters.
In the Frappe framework, Calendar and Gantt views are powerful tools for visualizing time-based data. These views are not magic; they are powered by a dedicated server-side Python method that fetches and formats the necessary event data. This method is typically named `get_events`.
This snippet demonstrates the standard structure of a `get_events` function. It's a whitelisted server script that accepts start and end date parameters from the calendar UI, executes a custom SQL query to retrieve relevant records, and returns them in a format that the calendar component can render.
1 import frappe 2 import json 3
4 @frappe.whitelist() 5 def get_events(start, end, filters=None): 6 """Returns events for Gantt / Calendar view rendering. 7 :param start: Start date-time. 8 :param end: End date-time. 9 :param filters: Filters (JSON). 10 """ 11 filters = json.loads(filters) if filters else {} 12
13 # Note: get_conditions is a hypothetical helper function to build WHERE clauses 14 # You would implement this based on the filters your calendar needs. 15 # from frappe.desk.calendar import get_event_conditions 16 # conditions = get_event_conditions("Timesheet", filters) 17
18 conditions = "" 19 # Example of building conditions from filters 20 # if filters.get('project'): 21 # conditions += f" AND project = '{filters.get('project')}'" 22
23 return frappe.db.sql("""select 24 `tabTimesheet Detail`.name as name, 25 `tabTimesheet Detail`.docstatus as status, 26 `tabTimesheet Detail`.parent as parent, 27 from_time as start_date, 28 hours, 29 activity_type, 30 project, 31 to_time as end_date, 32 CONCAT(`tabTimesheet Detail`.parent, ' (', ROUND(hours,2),' hrs)') as title 33 from `tabTimesheet Detail`, `tabTimesheet` 34 where `tabTimesheet Detail`.parent = `tabTimesheet`.name 35 and `tabTimesheet`.docstatus < 2 36 and (from_time <= %(end)s and to_time >= %(start)s) {conditions} 37 """.format(conditions=conditions), 38 { 39 "start": start, 40 "end": end 41 }, as_dict=True, update={"allDay": 0})
Understanding This Code
What It Does
This Python method fetches records from the Timesheet DocType, formatted as events, for rendering in Frappe's standard Calendar or Gantt views.
When To Use
Use this pattern when creating a custom calendar view for any DocType. This server-side script is required and must be paired with a corresponding client-side JavaScript file that configures the calendar view.
Prerequisites
- •A DocType with date or datetime fields (e.g., start_date, end_date).
- •Basic understanding of Frappe's server-side scripting.
- •Familiarity with SQL queries.
Key Concepts
Important ideas to understand in this code
@frappe.whitelist() Decorator
This decorator is a security feature that exposes a Python function to be called from the client-side (JavaScript) via an AJAX request. Any method intended to be called from the UI must be 'whitelisted'.
Learn morefrappe.db.sql
A Frappe API method used to execute raw SQL queries against the database. It's highly flexible and often necessary for calendar views which require specific field aliases (like 'title', 'start_date') and complex joins.
Learn moreCalendar View Client Script
This Python script is only the backend part. To enable the view, you must also create a `[doctype_name]_calendar.js` file that tells the framework which DocType to use and which `get_events` method to call.
Learn moreStep-by-Step Tutorial
Follow along to understand how this code works
Create the Python Server Script File
In your custom app, navigate to the directory of the DocType you want a calendar for. Create or open the main Python file for that DocType (e.g., `my_app/my_app/doctype/meeting/meeting.py`).
# In my_app/my_app/doctype/meeting/meeting.py
import frappe
import jsonDefine and Whitelist the get_events Function
Add the get_events function and decorate it with `@frappe.whitelist()`. The function must accept `start`, `end`, and optional `filters` arguments.
@frappe.whitelist()
def get_events(start, end, filters=None):
pass # We will add the logic nextImplement the SQL Query
Use `frappe.db.sql` to fetch your data. Important: You must alias your date fields to start_date and end_date, and a descriptive field to title for the calendar to display them correctly.
return frappe.db.sql("""SELECT
name,
subject as title,
scheduled_from as start_date,
scheduled_to as end_date
FROM `tabMeeting`
WHERE docstatus = 1 AND (scheduled_from <= %(end)s AND scheduled_to >= %(start)s)
""", {"start": start, "end": end}, as_dict=True)Create the Calendar View JavaScript File
In the same DocType directory, create a new file named `[doctype_name]_calendar.js` (e.g., `meeting_calendar.js`). This file configures the frontend calendar.
// In my_app/my_app/doctype/meeting/meeting_calendar.js
// This file should intentionally be left blank if you only need a basic calendar.
// Frappe will automatically use the get_events method if it exists.(Optional) Configure Advanced Calendar Settings
For more control, you can define the calendar view settings explicitly in your JS file, including the path to your `get_events` method.
frappe.views.calendar["Meeting"] = {
get_events: "my_app.my_app.doctype.meeting.meeting.get_events",
field_map: {
"start": "start_date",
"end": "end_date",
"id": "name",
"title": "title",
},
};Common Issues & Solutions
Troubleshoot problems you might encounter