Mastering Frappe Framework – Part 2: Understanding Frappe Architecture

Why Understanding Frappe’s Architecture Matters

Many beginners jump straight into creating DocTypes and scripts without understanding how Frappe’s components fit together.

If you understand how data flows and which layer does what, you’ll:

  • Write cleaner, more maintainable code
  • Debug faster when things go wrong
  • Use built-in features effectively instead of reinventing them

The Building Blocks of Frappe

The Frappe Framework follows an MVC-inspired architecture (Model-View-Controller) — but with its own twist.

1. 

DocType (Model)

  • Represents both a database table and its business logic.
  • Defined in JSON + Python.
  • Automatically creates:
    • Database schema (MariaDB table)
    • API endpoints (/api/resource/<doctype>)
    • UI forms in the admin panel

Example:

If you create a Customer DocType with fields like Name, Email, and Phone:

  • Frappe will create a table tabCustomer
  • You’ll get API routes:
    • GET /api/resource/Customer
    • POST /api/resource/Customer

2. 

Controllers (Python Classes)

  • Each DocType can have a Python controller file: customer.py
  • This file contains server-side methods and event hooks:
    • before_save(self) → runs before saving a document
    • on_update(self) → runs after a document is updated
    • validate(self) → runs before saving, used for data checks

3. 

Views (UI Layer)

  • Generated automatically for each DocType.
  • You can customize them using:
    • Client Scripts (JavaScript)
    • Custom Pages (Jinja + HTML + JS)

4. 

REST API

  • Every DocType automatically gets a CRUD API.
  • Example:
curl -X GET \
  https://mysite.com/api/resource/Customer \
  -H "Authorization: token <api_key>:<api_secret>"



You can also create whitelisted methods for custom APIs.
The Frappe Request Lifecycle

Understanding what happens when you click “Save” in Frappe is important.

Step-by-step:

  1. User Action – You submit a form in the web UI (or call an API).
  2. Router – Frappe determines the endpoint and which handler to call.
  3. Permission Check – The framework checks user roles and permissions.
  4. Controller Hooks – Runs event methods (validate, before_save, on_update).
  5. Database Transaction – Data is committed to MariaDB.
  6. Post-Commit Actions – Emails, background jobs, webhooks, etc.
  7. Response Sent – The updated document is returned to the user.

Frappe ORM: The Magic Behind the Scenes

Instead of writing raw SQL, you use Frappe ORM (Object Relational Mapper).

Example: Fetch all Customers:

customers = frappe.get_all("Customer", fields=["name", "email"])


Create a new Customer:

doc = frappe.get_doc({
    "doctype": "Customer",
    "name": "John Doe",
    "email": "john@example.com"
})
doc.insert()


This keeps your code clean and database-agnostic.

Events & Hooks: The Glue of Frappe

Events in Frappe allow you to run code when certain actions happen.

Common Server-Side Events:

  • before_insert
  • validate
  • on_submit
  • on_cancel
  • on_trash

Example: Auto-fill a field before save

def before_save(self):
    self.full_name = f"{self.first_name} {self.last_name}"

Putting It All Together

When you build in Frappe:

  • DocType defines your data model.
  • Controller holds your server-side business logic.
  • Client Script makes the UI interactive.
  • Frappe ORM & API handle data transfer between frontend and backend.

What’s Next?

In Part 3, we’ll get our hands dirty and create your first Frappe App:

  • Setting up a custom DocType
  • Adding fields
  • Writing your first server and client scripts
  • Viewing your data in the UI and via API

Leave a Reply