用途
本技能用于在 Frappe/ERPNext 中从零构建自定义应用(custom app),提供 v14/v15/v16 版本的完整语法参考。当需要创建新的 Frappe/ERPNext 自定义应用、配置 pyproject.toml 或 setup.py、组织应用内的模块、编写数据库迁移补丁、配置 fixtures 数据导出/导入,或管理应用依赖时,可使用本技能。
本技能不适用于以下场景:DocType 控制器(应使用 erpnext-syntax-controllers)、客户端脚本(应使用 erpnext-syntax-clientscripts)、服务器脚本(应使用 erpnext-syntax-serverscripts)、hooks 配置(应使用 erpnext-syntax-hooks)。
主要能力
应用结构
v15 以 pyproject.toml 为主要构建配置。典型目录结构如下:
apps/my_custom_app/
├── pyproject.toml # 构建配置
├── README.md
├── my_custom_app/ # 主包
│ ├── __init__.py # 必须包含 __version__!
│ ├── hooks.py # Frappe 集成
│ ├── modules.txt # 模块注册
│ ├── patches.txt # 迁移脚本
│ ├── patches/ # 补丁文件
│ ├── my_custom_app/ # 默认模块
│ │ └── doctype/
│ ├── public/ # 客户端资源
│ └── templates/ # Jinja 模板
└── .git/
关键文件
__init__.py 为必需文件,必须定义 __version__,否则 flit 构建会失败:
# my_custom_app/__init__.py
__version__ = "0.0.1"
pyproject.toml(v15)示例:
[build-system]
requires = ["flit_core >=3.4,<4"]
build-backend = "flit_core.buildapi"
[project]
name = "my_custom_app"
authors = [
{ name = "Your Company", email = "dev@example.com" }
]
description = "Description of your app"
requires-python = ">=3.10"
readme = "README.md"
dynamic = ["version"]
dependencies = []
[tool.bench.frappe-dependencies]
frappe = ">=15.0.0,<16.0.0"
erpnext = ">=15.0.0,<16.0.0"
模块组织
modules.txt 每行一个模块,名称中的空格在目录中对应下划线,每个 DocType 必须归属于某个模块。每个模块目录必须包含 __init__.py。
My Custom App
Integrations
Settings
Reports
补丁(迁移脚本)
patches.txt 使用 INI 分节:
[pre_model_sync]
# 模式同步前 - 旧字段仍可用
myapp.patches.v1_0.backup_old_data
[post_model_sync]
# 模式同步后 - 新字段可用
myapp.patches.v1_0.populate_new_fields
myapp.patches.v1_0.cleanup_data
补丁实现示例:
# myapp/patches/v1_0/populate_new_fields.py
import frappe
def execute():
"""Populate new fields with default values."""
batch_size = 1000
offset = 0
while True:
records = frappe.get_all(
"MyDocType",
filters={"new_field": ["is", "not set"]},
fields=["name"],
limit_page_length=batch_size,
limit_start=offset
)
if not records:
break
for record in records:
frappe.db.set_value(
"MyDocType",
record.name,
"new_field",
"default_value",
update_modified=False
)
frappe.db.commit()
offset += batch_size
pre_model_sync 与 post_model_sync 的选择:从旧字段迁移数据用 pre_model_sync;填充新字段、数据清理用 post_model_sync。
Fixtures
在 hooks.py 中配置:
fixtures = [
# 所有记录
"Category",
# 带过滤条件
{
"dt": "Custom Field",
"filters": [["module", "=", "My Custom App"]]
},
# 多个过滤条件
{
"dt": "Property Setter",
"filters": [
["module", "=", "My Custom App"],
["doc_type", "in", ["Sales Invoice", "Sales Order"]]
]
}
]
导出命令:
bench --site mysite export-fixtures --app my_custom_app
常见 fixture DocType 包括 Custom Field(现有 DocType 上的自定义字段)、Property Setter(修改字段属性)、Role(自定义角色)、Workflow(工作流定义)。
最小 hooks.py
app_name = "my_custom_app"
app_title = "My Custom App"
app_publisher = "Your Company"
app_description = "Description"
app_email = "dev@example.com"
app_license = "MIT"
required_apps = ["frappe"] # 或 ["frappe", "erpnext"]
fixtures = [
{"dt": "Custom Field", "filters": [["module", "=", "My Custom App"]]}
]
使用方式
创建并安装应用:
# 创建新应用
bench new-app my_custom_app
# 在站点上安装
bench --site mysite install-app my_custom_app
# 迁移(补丁 + fixtures)
bench --site mysite migrate
# 构建资源
bench build --app my_custom_app
版本差异
| 方面 | v14 | v15 |
|---|---|---|
| 构建配置 | setup.py | pyproject.toml |
| 依赖 | requirements.txt | 在 pyproject.toml 中 |
| 构建后端 | setuptools | flit_core |
| Python 最低版本 | >=3.10 | >=3.10 |
| INI 补丁 | ✅ | ✅ |
关键规则
应始终:在 __init__.py 中定义 __version__;在 pyproject.toml 中添加 dynamic = ["version"];在 modules.txt 中注册模块;每个目录都包含 __init__.py;将 Frappe 依赖放在 [tool.bench.frappe-dependencies];在补丁中添加错误处理;对大数据集使用批处理。
不应:将 Frappe/ERPNext 放入项目依赖(它们不在 PyPI 上);创建无错误处理的补丁;在 fixtures 中包含用户/事务数据;硬编码站点特定值;不批处理地处理大数据集。
Fixtures 与 Patches 的区分
| 内容 | Fixtures | Patches |
|---|---|---|
| 自定义字段 | ✅ | ❌ |
| 属性设置器 | ✅ | ❌ |
| 角色/工作流 | ✅ | ❌ |
| 数据转换 | ❌ | ✅ |
| 数据清理 | ❌ | ✅ |
| 一次性迁移 | ❌ | ✅ |
适用场景与限制
适用场景:创建新的 Frappe/ERPNext 自定义应用、配置构建文件、组织模块、编写迁移补丁、配置 fixtures、管理应用依赖。
限制:本技能不覆盖 DocType 控制器、客户端脚本、服务器脚本和 hooks 配置,这些需使用对应的独立技能。参考文件包括 references/structure.md(完整目录结构)、references/pyproject-toml.md(构建配置选项)、references/modules.md(模块组织)、references/patches.md(迁移脚本)、references/fixtures.md(数据导出/导入)、references/examples.md(完整应用示例)、references/anti-patterns.md(应避免的错误)。相关技能:erpnext-syntax-hooks(hooks.py 配置)、erpnext-syntax-controllers(DocType 控制器)、erpnext-impl-customapp(实现模式)。