mcpField
F
frappe-syntax-doctypes

frappe-syntax-doctypes

github.com/impertio-studio开发198118 次安装30 周前更新
代码仓库

关于 frappe-syntax-doctypes

面向 Frappe 应用开发者的 DocType JSON 设计参考,涵盖数据模型、表单字段、命名规则及常见 DocType 类型,帮助在编写控制器逻辑前规划结构。

主要功能

  1. 01DocType 顶层属性参考
  2. 02常用字段类型与属性
  3. 03命名规则和模式示例
  4. 04子表、单例及树形设计
  5. 05自定义字段与属性设置
  6. 06虚拟 DocType 和类型标注

适用场景

  1. 01规划应用的数据结构
  2. 02配置字段和表单行为
  3. 03设计命名与子表关系
  4. 04为现有 DocType 添加自定义字段

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/impertio-studio/frappe_claude_skill_package --skill frappe-syntax-doctypes

安装后在 Claude Code 中输入/frappe-syntax-doctypes确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
.gitkeep
anti-patterns.md
customization.md
data-masking.md
examples.md
fieldtypes.md
naming.md
type-stubs.md

详细介绍

DocType JSON 设计

DocType 是每个 Frappe 应用的基础。DocType 同时定义数据模型(数据库架构)和视图(表单布局)。务必先设计 DocType,再编写任何控制器逻辑。

快速参考

DocType JSON 顶层属性
属性类型用途
namestrDocType 标识符(单数形式,例如 "Sales Invoice")
modulestr此 DocType 所属的应用模块
is_submittablebool启用 Draft -> Submitted -> Cancelled 工作流
is_treebool启用 NestedSet 层级结构(lft/rgt 列)
is_virtualbool无数据库表;数据来自自定义后端
issinglebool单实例设置文档
istablebool子表 DocType(嵌入父文档中)
is_calendar_and_ganttbool启用日历/甘特图视图
track_changesbool每次保存时存储版本历史
track_seenbool跟踪哪些用户查看过此文档
track_viewsbool统计文档总浏览次数
allow_renamebool允许创建后重命名
allow_copybool启用“复制”操作
allow_importbool为此 DocType 启用数据导入
naming_rulestr命名方法选择器(参见“命名”部分)
autonamestr命名模式字符串
title_fieldstr用作显示标题的字段
search_fieldsstr用于搜索结果的逗号分隔字段
show_title_field_in_linkbool在 Link 字段中显示标题而非名称
image_fieldstr包含头像图片的字段
sort_fieldstr默认排序列
sort_orderstr"ASC" 或 "DESC"
default_print_formatstrPrint Format 名称
max_attachmentsint附件数量上限
常见字段类型(快速查询)
字段类型存储内容数据库列
Data最多 140 个字符的文本VARCHAR(140)
Link对另一个 DocType 的引用VARCHAR(140)
Dynamic Link对任意 DocType 的引用VARCHAR(140)
Select从选项中单选VARCHAR(140)
Table子表行独立表
Table MultiSelect多选链接行独立表
Check布尔值 0/1TINYINT
Int整数INT
Float小数(9 位)DECIMAL
Currency金额(6 位小数)DECIMAL
Date日历日期DATE
Datetime日期 + 时间DATETIME
Text Editor富文本(HTML)LONGTEXT
Attach文件引用VARCHAR(140)
Small Text简短多行文本TEXT
Long Text无限长度文本LONGTEXT

包含 35 种以上类型的完整字段类型参考:references/fieldtypes.md

基本字段属性
属性类型用途
reqdbool字段为必填项
uniquebool数据库 UNIQUE 约束
search_indexbool为数据库创建 INDEX 以加快查询
in_list_viewbool在列表视图列中显示
in_standard_filterbool在列表视图中显示为筛选条件
in_previewbool在文档预览中显示
allow_on_submitbool提交后可编辑
read_onlybool用户不可编辑
hiddenbool不在表单中显示
depends_onstr可见性条件(例如 eval:doc.status=="Active")
mandatory_depends_onstr条件必填
read_only_depends_onstr条件只读
fetch_fromstr从关联文档自动填充(例如 customer.customer_name)
fetch_if_emptybool仅在字段为空时获取
optionsstr特定于字段类型的选项(DocType 名称、选择项等)
defaultstr默认值(支持 __user、Today 等)
descriptionstr显示在字段下方的帮助文本
collapsiblebool区块默认折叠(仅适用于 Section Break)

决策树:选择哪种 DocType?

Need to store data?
├─ YES: Need multiple records?
│  ├─ YES: Need submit/cancel workflow?
│  │  ├─ YES → Standard DocType + is_submittable=1
│  │  └─ NO: Need hierarchy/tree?
│  │     ├─ YES → Tree DocType (is_tree=1)
│  │     └─ NO: Embedded in parent?
│  │        ├─ YES → Child DocType (istable=1)
│  │        └─ NO → Standard DocType
│  └─ NO: Single config/settings → Single DocType (issingle=1)
└─ NO: Data from external source → Virtual DocType (is_virtual=1)

命名规则

始终在 DocType 上设置 naming_rule。autoname 字段用于存放模式。

naming_rule 值autoname 模式示例输出
Set by User(empty)用户手动输入名称
Autoincrement(empty)1、2、3
By Fieldnamefield:{fieldname}该字段的值
By Naming Seriesnaming_series:INV-2024-00001(来自序列字段)
ExpressionPRE-.#####PRE-00001、PRE-00002
Expression (Old Style){prefix}-{YYYY}-{#####}INV-2024-00001
Randomhash随机 10 字符字符串
UUID(empty)550e8400-e29b-...
By Script(custom)由控制器的 autoname() 决定

绝不要在生产环境中使用 Autoincrement——删除记录后会出现间隙。请改用 Expression 或 Naming Series。

完整命名参考:references/naming.md

子表设计

Child DocType 是设置了 istable=1 的 DocType。它始终属于某个父项。

父项一侧——添加一个字段,设置:

  • fieldtype:Table(或 Table MultiSelect)
  • options:Child DocType 名称

子记录会自动获得:

  • parent——父文档的名称
  • parenttype——父项的 DocType
  • parentfield——父项中 Table 字段的 fieldname
  • idx——行顺序(从 1 开始)
# Adding child rows programmatically
doc = frappe.get_doc("Sales Invoice", "INV-001")
doc.append("items", {
    "item_code": "ITEM-001",
    "qty": 5,
    "rate": 100.0
})
doc.save()

绝不要创建未设置 istable=1 的 Child DocType。绝不要在 Table 字段中引用非子项 DocType。

Table 与 Table MultiSelect
方面TableTable MultiSelect
UI完整可编辑网格,带有“添加行”标签式选择器,没有“添加行”
Child DocType包含多个字段的完整子项通常仅包含 1 个 Link 字段
使用场景行项目、明细行多选引用

Single DocType(设置模式)

设置 issingle=1。数据以键值对形式存储在 tabSingles 中,而非专用表中。

# Access Single DocType
settings = frappe.get_single("My Settings")
value = settings.some_field

# Or directly
value = frappe.db.get_single_value("My Settings", "some_field")
  • 绝不要期待 Single DocType 有列表视图——它们恰好只有一个实例。
  • 始终将其用于应用级配置(API 密钥、默认值、功能开关)。

Tree DocType(NestedSet)

设置 is_tree=1。Frappe 会自动添加 lft、rgt、parent_{doctype_fieldname}、old_parent 列。

  • 始终在 DocType JSON 中定义 parent_field(例如,为 Chart of Accounts 定义 parent_account)。
  • NestedSet 模型使用 lft/rgt 整数来高效查询子树。
  • 绝不要手动编辑 lft/rgt 值。如果数据损坏,请使用 frappe.utils.nestedset.rebuild_tree()。
# Get all descendants
descendants = frappe.get_all("Account",
    filters={"lft": [">", node.lft], "rgt": ["<", node.rgt]})

# Get ancestors (path to root)
ancestors = frappe.get_all("Account",
    filters={"lft": ["<", node.lft], "rgt": [">", node.rgt]},
    order_by="lft asc")

Virtual DocType

设置 is_virtual=1。不会创建数据库表。始终实现以下控制器方法:

class MyVirtualDoc(Document):
    def db_insert(self, *args, **kwargs):
        # Persist to your custom backend
        pass

    def load_from_db(self):
        # Load document data from your source
        pass

    def db_update(self, *args, **kwargs):
        # Update in your custom backend
        pass

    def delete(self):
        # Remove from your custom backend
        pass

    @staticmethod
    def get_list(args):
        # Return list of documents
        pass

    @staticmethod
    def get_count(args):
        # Return total count
        pass

    @staticmethod
    def get_stats(args):
        # Return statistics
        pass

绝不要对 Virtual DocType 数据调用 frappe.db.*——这些调用只适用于站点数据库,不适用于自定义后端。

自定义 API

自定义字段(程序化)
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields

# Dict format: {DocType: [field_dicts]}
create_custom_fields({
    "Sales Invoice": [
        dict(fieldname="custom_tracking", label="Tracking ID",
             fieldtype="Data", insert_after="naming_series")
    ],
    "Purchase Order": [
        dict(fieldname="custom_vendor_ref", label="Vendor Ref",
             fieldtype="Data", insert_after="supplier")
    ]
}, update=True)
Property Setter(程序化)
from frappe.custom.doctype.property_setter.property_setter import make_property_setter

# Change a field property on an existing DocType
make_property_setter("Sales Invoice", "customer", "reqd", 1, "Check")
make_property_setter("Sales Invoice", "posting_date", "default", "Today", "Text")

完整自定义参考:references/customization.md

数据遮蔽(v16+)

设置了 mask=1 的字段,会向在该字段的 permlevel 上没有 mask 权限的用户隐藏敏感值。服务器会在向客户端发送值前,将其替换为 XXXXXXXX 等模式。管理员始终可以看到未遮蔽的值。

{ "fieldname": "phone", "fieldtype": "Data", "options": "Phone", "mask": 1, "permlevel": 1 }

完整遮蔽参考:references/data-masking.md

Python 类型存根

Frappe 会通过 TypeExporter 在控制器文件中自动生成类型注解。字段会在 TYPE_CHECKING 守卫内获得 DF.* 类型:

if TYPE_CHECKING:
    from frappe.types import DF
    customer: DF.Link
    items: DF.Table[SalesInvoiceItem]
    status: DF.Literal["Draft", "Submitted", "Paid"]

绝不要修改 # begin: auto-generated types 与 # end: auto-generated types 之间的代码。

完整类型存根参考:references/type-stubs.md

关键规则

  1. 始终以单数形式命名 DocType(“Sales Invoice”,而不是“Sales Invoices”)。
  2. 始终在脑中加上 tab 前缀——数据库表是 tabSales Invoice。
  3. Data/Link/Select 字段值的长度不得超过 140 个字符。
  4. 对频繁用于筛选或 get_list 调用的字段,始终设置 search_index=1。
  5. 对用户经常筛选的字段,始终设置 in_standard_filter=1。
  6. 子表字段若会影响计算,且不会重新计算总计,则绝不要设置 allow_on_submit=1。
  7. 除非希望覆盖用户的编辑,否则始终在 fetch_from 旁设置 fetch_if_empty=1。
  8. 绝不要使用原始 Python 定义 depends_on——请使用 eval:doc.fieldname == "value" 语法。

另请参阅

评论

支持 Markdown