@@ -14,16 +14,278 @@ metadata:
1414
1515# DocType JSON Design
1616
17- > ** STATUS ** : Stub - content pending V2.5 development phase .
17+ DocTypes are the foundation of every Frappe application. A DocType defines both the ** data model ** (database schema) and the ** view ** (form layout). ALWAYS design DocTypes before writing any controller logic .
1818
1919## Quick Reference
2020
21- _ Content to be developed. _
21+ ### DocType JSON Top-Level Properties
2222
23- ## Decision Tree
23+ | Property | Type | Purpose |
24+ | ----------| ------| ---------|
25+ | ` name ` | str | DocType identifier (singular, e.g. "Sales Invoice") |
26+ | ` module ` | str | App module this DocType belongs to |
27+ | ` is_submittable ` | bool | Enables Draft -> Submitted -> Cancelled workflow |
28+ | ` is_tree ` | bool | Enables NestedSet hierarchy (lft/rgt columns) |
29+ | ` is_virtual ` | bool | No database table; data from custom backend |
30+ | ` issingle ` | bool | Single-instance settings document |
31+ | ` istable ` | bool | Child table DocType (embedded in parent) |
32+ | ` is_calendar_and_gantt ` | bool | Enables calendar/gantt views |
33+ | ` track_changes ` | bool | Stores version history on every save |
34+ | ` track_seen ` | bool | Tracks which users viewed the document |
35+ | ` track_views ` | bool | Counts total document views |
36+ | ` allow_rename ` | bool | Permits renaming after creation |
37+ | ` allow_copy ` | bool | Enables "Duplicate" action |
38+ | ` allow_import ` | bool | Enables Data Import for this DocType |
39+ | ` naming_rule ` | str | Naming method selector (see Naming section) |
40+ | ` autoname ` | str | Naming pattern string |
41+ | ` title_field ` | str | Field used as display title |
42+ | ` search_fields ` | str | Comma-separated fields for search results |
43+ | ` show_title_field_in_link ` | bool | Display title instead of name in Link fields |
44+ | ` image_field ` | str | Field containing image for avatar display |
45+ | ` sort_field ` | str | Default sort column |
46+ | ` sort_order ` | str | "ASC" or "DESC" |
47+ | ` default_print_format ` | str | Print Format name |
48+ | ` max_attachments ` | int | Attachment limit |
2449
25- _ Content to be developed._
50+ ### Common Fieldtypes (Quick Lookup)
51+
52+ | Fieldtype | Stores | DB Column |
53+ | -----------| --------| -----------|
54+ | Data | Text up to 140 chars | VARCHAR(140) |
55+ | Link | Reference to another DocType | VARCHAR(140) |
56+ | Dynamic Link | Reference to any DocType | VARCHAR(140) |
57+ | Select | Single choice from options | VARCHAR(140) |
58+ | Table | Child table rows | Separate table |
59+ | Table MultiSelect | Multi-select link rows | Separate table |
60+ | Check | Boolean 0/1 | TINYINT |
61+ | Int | Whole number | INT |
62+ | Float | Decimal (9 places) | DECIMAL |
63+ | Currency | Money value (6 decimals) | DECIMAL |
64+ | Date | Calendar date | DATE |
65+ | Datetime | Date + time | DATETIME |
66+ | Text Editor | Rich text (HTML) | LONGTEXT |
67+ | Attach | File reference | VARCHAR(140) |
68+ | Small Text | Short multi-line text | TEXT |
69+ | Long Text | Unlimited text | LONGTEXT |
70+
71+ > Full fieldtype reference with all 35+ types: [ references/fieldtypes.md] ( references/fieldtypes.md )
72+
73+ ### Essential Field Properties
74+
75+ | Property | Type | Purpose |
76+ | ----------| ------| ---------|
77+ | ` reqd ` | bool | Field is mandatory |
78+ | ` unique ` | bool | Database UNIQUE constraint |
79+ | ` search_index ` | bool | Database INDEX for faster queries |
80+ | ` in_list_view ` | bool | Show in list view columns |
81+ | ` in_standard_filter ` | bool | Show as filter in list view |
82+ | ` in_preview ` | bool | Show in document preview |
83+ | ` allow_on_submit ` | bool | Editable after submission |
84+ | ` read_only ` | bool | Not editable by user |
85+ | ` hidden ` | bool | Not visible on form |
86+ | ` depends_on ` | str | Visibility condition (e.g. ` eval:doc.status=="Active" ` ) |
87+ | ` mandatory_depends_on ` | str | Conditional mandatory |
88+ | ` read_only_depends_on ` | str | Conditional read-only |
89+ | ` fetch_from ` | str | Auto-populate from linked doc (e.g. ` customer.customer_name ` ) |
90+ | ` fetch_if_empty ` | bool | Only fetch when field is empty |
91+ | ` options ` | str | Fieldtype-specific (DocType name, select options, etc.) |
92+ | ` default ` | str | Default value (supports ` __user ` , ` Today ` , etc.) |
93+ | ` description ` | str | Help text below field |
94+ | ` collapsible ` | bool | Section starts collapsed (Section Break only) |
95+
96+ ## Decision Tree: Which DocType Type?
97+
98+ ```
99+ Need to store data?
100+ ├─ YES: Need multiple records?
101+ │ ├─ YES: Need submit/cancel workflow?
102+ │ │ ├─ YES → Standard DocType + is_submittable=1
103+ │ │ └─ NO: Need hierarchy/tree?
104+ │ │ ├─ YES → Tree DocType (is_tree=1)
105+ │ │ └─ NO: Embedded in parent?
106+ │ │ ├─ YES → Child DocType (istable=1)
107+ │ │ └─ NO → Standard DocType
108+ │ └─ NO: Single config/settings → Single DocType (issingle=1)
109+ └─ NO: Data from external source → Virtual DocType (is_virtual=1)
110+ ```
111+
112+ ## Naming Rules
113+
114+ ALWAYS set ` naming_rule ` on the DocType. The ` autoname ` field holds the pattern.
115+
116+ | naming_rule Value | autoname Pattern | Example Output |
117+ | -------------------| ------------------| ----------------|
118+ | Set by User | _ (empty)_ | User types name manually |
119+ | Autoincrement | _ (empty)_ | ` 1 ` , ` 2 ` , ` 3 ` |
120+ | By Fieldname | ` field:{fieldname} ` | Value of that field |
121+ | By Naming Series | ` naming_series: ` | ` INV-2024-00001 ` (from series field) |
122+ | Expression | ` PRE-.##### ` | ` PRE-00001 ` , ` PRE-00002 ` |
123+ | Expression (Old Style) | ` {prefix}-{YYYY}-{#####} ` | ` INV-2024-00001 ` |
124+ | Random | ` hash ` | Random 10-char string |
125+ | UUID | _ (empty)_ | ` 550e8400-e29b-... ` |
126+ | By Script | _ (custom)_ | Controller ` autoname() ` decides |
127+
128+ > NEVER use Autoincrement in production -- gaps appear when records are deleted. Use Expression or Naming Series instead.
129+
130+ > Full naming reference: [ references/naming.md] ( references/naming.md )
131+
132+ ## Child Table Design
133+
134+ A Child DocType is a DocType with ` istable=1 ` . It ALWAYS belongs to a parent.
135+
136+ ** Parent side** -- add a field with:
137+ - ` fieldtype ` : ` Table ` (or ` Table MultiSelect ` )
138+ - ` options ` : Child DocType name
139+
140+ ** Child records automatically get** :
141+ - ` parent ` -- name of the parent document
142+ - ` parenttype ` -- DocType of the parent
143+ - ` parentfield ` -- fieldname of the Table field in parent
144+ - ` idx ` -- row order (1-based)
145+
146+ ``` python
147+ # Adding child rows programmatically
148+ doc = frappe.get_doc(" Sales Invoice" , " INV-001" )
149+ doc.append(" items" , {
150+ " item_code" : " ITEM-001" ,
151+ " qty" : 5 ,
152+ " rate" : 100.0
153+ })
154+ doc.save()
155+ ```
156+
157+ > NEVER create a Child DocType without ` istable=1 ` . NEVER reference a non-child DocType in a Table field.
158+
159+ ### Table vs Table MultiSelect
160+
161+ | Aspect | Table | Table MultiSelect |
162+ | --------| -------| -------------------|
163+ | UI | Full editable grid with "Add Row" | Tag-style picker, no "Add Row" |
164+ | Child DocType | Full child with many fields | Typically 1 Link field only |
165+ | Use case | Line items, detail rows | Multi-select references |
166+
167+ ## Single DocType (Settings Pattern)
168+
169+ Set ` issingle=1 ` . Data is stored in ` tabSingles ` as key-value pairs, NOT in a dedicated table.
170+
171+ ``` python
172+ # Access Single DocType
173+ settings = frappe.get_single(" My Settings" )
174+ value = settings.some_field
175+
176+ # Or directly
177+ value = frappe.db.get_single_value(" My Settings" , " some_field" )
178+ ```
179+
180+ - NEVER expect a list view for Single DocTypes -- they have exactly one instance.
181+ - ALWAYS use for app-wide configuration (API keys, default values, feature toggles).
182+
183+ ## Tree DocType (NestedSet)
184+
185+ Set ` is_tree=1 ` . Frappe adds ` lft ` , ` rgt ` , ` parent_{doctype_fieldname} ` , ` old_parent ` columns automatically.
186+
187+ - ALWAYS define a ` parent_field ` in the DocType JSON (e.g. ` parent_account ` for Chart of Accounts).
188+ - The NestedSet model uses ` lft ` /` rgt ` integers for efficient subtree queries.
189+ - NEVER manually edit ` lft ` /` rgt ` values. Use ` frappe.utils.nestedset.rebuild_tree() ` if corrupted.
190+
191+ ``` python
192+ # Get all descendants
193+ descendants = frappe.get_all(" Account" ,
194+ filters = {" lft" : [" >" , node.lft], " rgt" : [" <" , node.rgt]})
195+
196+ # Get ancestors (path to root)
197+ ancestors = frappe.get_all(" Account" ,
198+ filters = {" lft" : [" <" , node.lft], " rgt" : [" >" , node.rgt]},
199+ order_by = " lft asc" )
200+ ```
201+
202+ ## Virtual DocType
203+
204+ Set ` is_virtual=1 ` . No database table is created. ALWAYS implement these controller methods:
205+
206+ ``` python
207+ class MyVirtualDoc (Document ):
208+ def db_insert (self , * args , ** kwargs ):
209+ # Persist to your custom backend
210+ pass
211+
212+ def load_from_db (self ):
213+ # Load document data from your source
214+ pass
215+
216+ def db_update (self , * args , ** kwargs ):
217+ # Update in your custom backend
218+ pass
219+
220+ def delete (self ):
221+ # Remove from your custom backend
222+ pass
223+
224+ @ staticmethod
225+ def get_list (args ):
226+ # Return list of documents
227+ pass
228+
229+ @ staticmethod
230+ def get_count (args ):
231+ # Return total count
232+ pass
233+
234+ @ staticmethod
235+ def get_stats (args ):
236+ # Return statistics
237+ pass
238+ ```
239+
240+ > NEVER use ` frappe.db.* ` calls for Virtual DocType data -- they only work with the site database, not your custom backend.
241+
242+ ## Customization APIs
243+
244+ ### Custom Fields (Programmatic)
245+
246+ ``` python
247+ from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
248+
249+ # Dict format: {DocType: [field_dicts]}
250+ create_custom_fields({
251+ " Sales Invoice" : [
252+ dict (fieldname = " custom_tracking" , label = " Tracking ID" ,
253+ fieldtype = " Data" , insert_after = " naming_series" )
254+ ],
255+ " Purchase Order" : [
256+ dict (fieldname = " custom_vendor_ref" , label = " Vendor Ref" ,
257+ fieldtype = " Data" , insert_after = " supplier" )
258+ ]
259+ }, update = True )
260+ ```
261+
262+ ### Property Setter (Programmatic)
263+
264+ ``` python
265+ from frappe.custom.doctype.property_setter.property_setter import make_property_setter
266+
267+ # Change a field property on an existing DocType
268+ make_property_setter(" Sales Invoice" , " customer" , " reqd" , 1 , " Check" )
269+ make_property_setter(" Sales Invoice" , " posting_date" , " default" , " Today" , " Text" )
270+ ```
271+
272+ > Full customization reference: [ references/customization.md] ( references/customization.md )
273+
274+ ## Critical Rules
275+
276+ 1 . ALWAYS name DocTypes in ** singular** form ("Sales Invoice", not "Sales Invoices").
277+ 2 . ALWAYS use the ` tab ` prefix mentally -- the DB table is ` tabSales Invoice ` .
278+ 3 . NEVER exceed 140 characters for Data/Link/Select field values.
279+ 4 . ALWAYS set ` search_index=1 ` on fields used in frequent filters or ` get_list ` calls.
280+ 5 . ALWAYS set ` in_standard_filter=1 ` on fields users frequently filter by.
281+ 6 . NEVER use ` allow_on_submit=1 ` on child table fields that affect calculations without recalculating totals.
282+ 7 . ALWAYS set ` fetch_if_empty=1 ` alongside ` fetch_from ` unless you want to overwrite user edits.
283+ 8 . NEVER define ` depends_on ` with raw Python -- use ` eval:doc.fieldname == "value" ` syntax.
26284
27285## See Also
28286
29- _ Cross-references to be added._
287+ - [ references/fieldtypes.md] ( references/fieldtypes.md ) -- Complete fieldtype reference
288+ - [ references/naming.md] ( references/naming.md ) -- All naming methods with examples
289+ - [ references/examples.md] ( references/examples.md ) -- Real DocType JSON examples
290+ - [ references/anti-patterns.md] ( references/anti-patterns.md ) -- Common schema design mistakes
291+ - [ references/customization.md] ( references/customization.md ) -- Custom Fields and Property Setter APIs
0 commit comments