Skip to main content

Frappe Framework v15 Document API

A complete, technically accurate guide for ERPNext developers, app builders, and integrators.

Introduction: What is the Document API in Frappe v15?

The Document API is the core interface for creating, reading, updating, deleting, submitting, canceling, and manipulating database records in Frappe. Every record in the framework—such as ToDo, Sales Invoice, User, Item—is represented as a DocType, and an instance of that record is represented as a Document object.

The Document API handles:

  • ORM-based database interactions
  • Permissions
  • Child tables
  • Workflows
  • Events (validate, before_save, on_submit, etc.)
  • Controller methods

This page explains how to use the full Frappe v15 Document API with precise syntax and examples.

How to Create a New Document in Frappe v15

Using frappe.new_doc()
doc = frappe.new_doc("ToDo")
doc.description = "Prepare documentation"
doc.date = "2025-03-10"
doc.insert()

  • Initializes a new document object
  • Does NOT save it until .insert() is called
  • Permissions are applied automatically

Using frappe.get_doc() with values
doc = frappe.get_doc({
"doctype": "ToDo",
"description": "Prepare docs",
"date": "2025-03-10"
})
doc.insert()

This is primarily used for building documents dynamically (e.g., API endpoints).

How to Load an Existing Document

Load by DocType and Name

doc = frappe.get_doc("ToDo", "TD-0001")

Load using dictionary format

(when receiving REST API payloads)

doc = frappe.get_doc(json_payload)

How to Modify and Save a Document

Update properties and save

doc = frappe.get_doc("ToDo", "TD-0001")
doc.description = "Updated description"
doc.save()

.save() triggers all standard controller events:

  • before_save
  • validate
  • on_update (if exists)

How to Submit, Cancel, and Amend Documents

Frappe uses a 3-stage lifecycle for documents that use Submit Workflow Logic (e.g., Sales Invoice, Purchase Order, Stock Entry).

Submit a document

doc = frappe.get_doc("Sales Invoice", "SINV-0001")
doc.submit()

Triggers:

  • before_submit
  • on_submit

Cancel a document

doc = frappe.get_doc("Sales Invoice", "SINV-0001")
doc.cancel()

Triggers:

  • before_cancel
  • on_cancel

Amend a document

doc = frappe.get_doc("Sales Invoice", "SINV-0001")
new_doc = doc.amend() # returns new draft document

Creates a new draft with reference to the old document.

Updating Documents Using db_set

Use db_set() when you want to override values directly in the database, bypassing validation events.
doc.db_set("status", "Closed")

This:

  • Updates in database immediately
  • Does NOT trigger validation
  • Optionally notifies via realtime

Useful for background jobs and system processes.

Working with Child Tables

Child tables are stored as dependent documents with parent, parenttype, and parentfield fields.

 Append a child row

doc = frappe.get_doc("Sales Invoice", "SINV-0001")
doc.append("items", {
"item_code": "ITEM-001",
"qty": 5,
"rate": 100
})
doc.save()

Loop through child table

for row in doc.items:
print(row.item_code, row.qty)

Document Methods & Controller API

Frappe allows adding custom business logic by defining methods inside the DocType’s Python controller.

Calling custom methods

doc = frappe.get_doc("ToDo", "TD-0001")
doc.run_reminder() # custom method inside ToDo.py

Methods receive the document as self.

Trigger validation manually

doc.validate()

However, Frappe automatically handles validation on save/submit.

Document Events (Server-Side Lifecycle Hooks)

Each controller can implement event functions such as:

  • validate
  • before_insert
  • after_insert
  • before_save
  • on_update
  • before_submit
  • on_submit
  • before_cancel
  • on_cancel
  • on_trash
  • after_delete

Events execute automatically based on actions performed via the Document API.

Accessing Metadata and Fields

List all fields

fields = doc.meta.fields

Get a specific field value

value = doc.get("description")

Set a field value

doc.set("description", "New value")

.set() does not bypass validation.

Permission Handling

Frappe validates permissions automatically when using:

  • frappe.get_doc()
  • .save()
  • .submit()
  • .cancel()

To bypass permission checks (system use only):

frappe.get_doc("ToDo", "TD-0001", for_update=True)

Or disable permission checks (use cautiously):

doc.flags.ignore_permissions = True
doc.save()

Deleting Documents

Soft delete (standard)

doc = frappe.get_doc("ToDo", "TD-0001")
doc.delete()

Triggers:
before_trash → deletes → after_delete

Hard delete (not recommended)

frappe.delete_doc("ToDo", "TD-0001", force=True)

Use only for system purges.

Advanced Usage & Integration Patterns

1. Using Document API in REST Endpoints

@frappe.whitelist()
def create_todo():
data = frappe.form_dict
doc = frappe.get_doc({
"doctype": "ToDo",
**data
})
doc.insert()
return doc

2. Using Document API inside Background Jobs

def process_invoice(inv):
doc = frappe.get_doc("Sales Invoice", inv)
doc.status = "Processing"
doc.save()

Recommended: add enqueue_after_commit=True when queueing jobs.

3. Creating Documents from Workflow Transitions

Used in ERPNext for Sales Cycle, Manufacturing, HR, etc.

new_doc = frappe.new_doc("Delivery Note")
new_doc.update_from_doc(source_doc, table_maps)
new_doc.insert()

Troubleshooting Common Issues

Validation Error on Save

Ensure mandatory fields are filled. Use doc.flags.ignore_validate = True only for system tasks.

PermissionError on Load

User lacks permission. Check Role Permission Manager.

Child Table Not Saved

Always call .save() after append().

Document Not Found

Check if the record is deleted or naming series is misconfigured.

Cross-References

  • Realtime API
  • Background Jobs
  • Permission API
  • Workflow API
  • REST API

Each interacts heavily with the Document API.

Conclusion

The Frappe v15 Document API is the backbone of ERPNext and all Frappe applications. It provides a rich, Pythonic ORM interface with built-in validation, event triggers, permissions, child table management, and workflow support. Mastering this API is essential for building robust ERP apps, automations, and custom business logic on the Frappe Framework.

Click to rate this post!
[Total: 0 Average: 0]