mcpField
F
frappe-app-development

frappe-app-development

github.com/lubusin开发69303 次安装12 周前更新
代码仓库

关于 frappe-app-development

frappe-app-development 是帮助开发者规划和构建自定义 Frappe 应用的技能,适用于从脚手架搭建到生产部署准备。内容涵盖分层架构、钩子、后台作业、通用工具及版本兼容性。

主要功能

  1. 01搭建应用脚手架并规划结构
  2. 02配置 hooks.py 与服务层
  3. 03设置后台作业和通用工具
  4. 04处理翻译及版本兼容性
  5. 05提供验证与故障排查指引

适用场景

  1. 01从零开始创建自定义 Frappe 应用
  2. 02组织 DocType、服务和业务逻辑
  3. 03为应用添加钩子及异步处理
  4. 04检查安装、迁移和后台作业问题

安装

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

$npx skills add https://github.com/lubusin/frappe-skills --skill frappe-app-development

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

包含的文件

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

assets/mini-app-template/your_app/
api.py
hooks.py
README.md
assets/mini-app-template/your_app/background_jobs/
sample_job.py
assets/mini-app-template/your_app/dashboard/
sample_doc_dashboard.json
assets/mini-app-template/your_app/doctype/sample_doc_item/
sample_doc_item.json
assets/mini-app-template/your_app/doctype/sample_doc/
sample_doc_dynamic_link.json
sample_doc_naming_series.json
sample_doc.js
sample_doc.json
sample_doc.py
assets/mini-app-template/your_app/doctype/sample_single/
sample_single.json
assets/mini-app-template/your_app/doctype/sample_submittable/
sample_submittable.json
assets/mini-app-template/your_app/doctype/sample_tree/
sample_tree.json
assets/mini-app-template/your_app/integrations/
sample_connector.py
assets/mini-app-template/your_app/list_view/
sample_doc_list.js
assets/mini-app-template/your_app/report/sample_report/
sample_report.js
sample_report.json
sample_report.py
assets/mini-app-template/your_app/services/
sample_service.py
assets/mini-app-template/your_app/utils/
cache.py
errors.py
logging.py
permissions.py
validation.py
assets/mini-app-template/your_app/workflow/
sample_doc_workflow.json
references/
app-development.md
translations.md
version-compat.md

详细介绍

Frappe 应用开发

使用生产级模式搭建、组织和设计自定义 Frappe 应用。

适用场景

  • 从头创建新的自定义 Frappe 应用
  • 设置应用架构(模块、服务、工具)
  • 配置 hooks.py,用于事件、调度器和覆盖项
  • 实现后台任务和异步处理
  • 构建服务层和领域逻辑模式
  • 添加缓存、日志记录、错误处理工具
  • 为生产环境部署准备应用
  • 管理翻译、版本控制和打包

所需输入

  • 应用名称和用途
  • 目标 Frappe 版本(v13+、v15+、v16+)
  • 模块结构(包含哪些 DocType、API、服务)
  • 是否需要其他应用的钩子/覆盖项
  • 后台任务要求
  • 生产就绪需求

流程

0) 搭建应用
# Create the app
bench new-app my_app

# Install on site
bench --site mysite.local install-app my_app

# Verify developer mode
bench --site mysite.local console
>>> frappe.conf.developer_mode  # Must be True
1) 规划应用结构

遵循领域架构模式——保持 DocType 控制器精简,并将业务逻辑放在服务模块中:

my_app/
├── my_app/
│   ├── __init__.py
│   ├── hooks.py              # App hooks and configuration
│   ├── api.py                # Public API surface (RPC endpoints)
│   ├── services/             # Business logic modules
│   │   └── billing.py
│   ├── utils/                # Cross-cutting utilities
│   │   ├── cache.py
│   │   ├── errors.py
│   │   ├── logging.py
│   │   ├── permissions.py
│   │   └── validation.py
│   ├── background_jobs/      # Async job handlers
│   │   └── export_job.py
│   ├── integrations/         # External system connectors
│   │   └── payment_gateway.py
│   ├── my_module/
│   │   ├── doctype/
│   │   │   └── my_doc/
│   │   │       ├── my_doc.json
│   │   │       ├── my_doc.py
│   │   │       ├── my_doc.js
│   │   │       └── test_my_doc.py
│   │   ├── report/
│   │   └── dashboard/
│   └── translations/
│       ├── en.csv
│       └── fr.csv
├── setup.py
└── README.md

使用 assets/mini-app-template/ 中的 mini-app-template 作为起始脚手架。

2) 配置 hooks.py
# hooks.py

app_name = "my_app"
app_title = "My App"
app_publisher = "My Company"

# DocType lifecycle events
doc_events = {
    "Sales Order": {
        "on_submit": "my_app.services.billing.on_order_submit",
        "on_cancel": "my_app.services.billing.on_order_cancel",
    },
    "*": {
        "after_insert": "my_app.utils.logging.log_creation",
    }
}

# Scheduled tasks
scheduler_events = {
    "daily": [
        "my_app.background_jobs.cleanup.run_daily_cleanup"
    ],
    "cron": {
        "0 */6 * * *": [
            "my_app.background_jobs.sync.sync_external_data"
        ]
    }
}

# Client-side script injection
doctype_js = {
    "Sales Order": "public/js/sales_order.js"
}

doctype_list_js = {
    "Sales Order": "public/js/sales_order_list.js"
}

# Override another app's controller (use sparingly)
# override_doctype_class = {
#     "ToDo": "my_app.overrides.custom_todo.CustomToDo"
# }

# Extend controller without full replacement (v16+, preferred)
# extend_doctype_class = {
#     "ToDo": "my_app.overrides.todo_extension.TodoExtension"
# }

# Override whitelisted methods
# override_whitelisted_methods = {
#     "frappe.client.get_list": "my_app.overrides.custom_get_list"
# }
3) 实现服务层

保持 DocType 控制器精简——将业务逻辑委托给服务:

# my_app/services/billing.py
import frappe

def on_order_submit(doc, method):
    """Handle order submission — called via doc_events hook."""
    if doc.grand_total > 10000:
        create_approval_request(doc)
    generate_invoice(doc)

def generate_invoice(order):
    """Create invoice from submitted order."""
    invoice = frappe.get_doc({
        "doctype": "Sales Invoice",
        "customer": order.customer,
        "items": [
            {"item_code": i.item_code, "qty": i.qty, "rate": i.rate}
            for i in order.items
        ]
    })
    invoice.insert()
    invoice.submit()
    return invoice
4) 设置后台任务
# my_app/background_jobs/export_job.py
import frappe

def enqueue_export(filters):
    """Enqueue a long-running export job."""
    frappe.enqueue(
        "my_app.background_jobs.export_job.run_export",
        filters=filters,
        queue="long",
        timeout=600,
        is_async=True
    )

def run_export(filters):
    """Execute the export — runs in background worker."""
    data = frappe.get_all("Sales Order", filters=filters, fields=["*"])
    # Process data...
    frappe.publish_realtime("export_complete", {"count": len(data)})
5) 添加横切工具
# my_app/utils/cache.py
import frappe

def get_cached_settings(key):
    """Cache expensive settings lookups."""
    value = frappe.cache().get_value(f"my_app:{key}")
    if value is None:
        value = frappe.db.get_single_value("My Settings", key)
        frappe.cache().set_value(f"my_app:{key}", value)
    return value

def invalidate_cache(key):
    frappe.cache().delete_value(f"my_app:{key}")
# my_app/utils/errors.py
import frappe

def api_error(message, status_code=400, exc=None):
    """Consistent error response for API endpoints."""
    frappe.local.response["http_status_code"] = status_code
    frappe.throw(message, exc or frappe.ValidationError)
6) 处理翻译
# In Python code
frappe._("Hello World")   # Mark string for translation

# In JavaScript
__("Hello World")         # Mark string for translation
# Translation CSV files go in my_app/translations/
# e.g., my_app/translations/fr.csv:
# Hello World,Bonjour le monde
7) 版本兼容性
功能最低版本
extend_doctype_classFrappe v16+
REST API v2(/api/v2/)Frappe v15+
基于令牌的身份验证Frappe v11.0.3+

面向多个版本时,应为特定版本的功能添加保护:

import frappe

if hasattr(frappe, 'extend_doctype_class'):
    # v16+ pattern
    pass
else:
    # Fallback for older versions
    pass

验证

  • 应用安装无错误:bench --site <site> install-app my_app
  • 钩子正常触发(检查调度器日志、文档事件)
  • 后台任务成功入队并完成
  • bench --site <site> migrate 执行成功
  • 测试通过:bench --site <site> run-tests --app my_app

故障模式 / 调试

  • 找不到应用:检查 apps.txt 和 sites/<site>/site_config.json
  • 钩子未触发:检查 hooks.py 语法;重启 bench
  • 后台任务卡住:使用 bench doctor 检查 worker 状态;确认 Redis 正常
  • 导入错误:确保 hooks 中的模块路径与实际 Python 路径一致
  • 未开启开发者模式:DocType 更改不会导出到文件

升级处理

  • 有关 DocType 创建详情 → frappe-doctype-development
  • 有关 API 端点模式 → frappe-api-development
  • 有关 Desk UI 自定义 → frappe-desk-customization
  • 有关 Frappe UI 前端 → frappe-frontend-development
  • 有关打印格式和 Jinja → frappe-printing-templates
  • 有关报表 → frappe-reports
  • 有关 Web 表单 → frappe-web-forms
  • 有关测试 → frappe-testing
  • 有关企业架构 → frappe-enterprise-patterns
  • 有关 Docker/FM 环境 → frappe-manager

参考资料

交叉引用(由专门技能维护)

防护规则

  • 自定义前端使用 Frappe UI:切勿使用原生 JS、jQuery 或自定义框架。Frappe UI(Vue 3 + TailwindCSS)是生态系统标准。设置方法请参阅 frappe-frontend-development。
  • CRUD 应用遵循 CRM/Helpdesk 模式:遵循 frappe-ui-patterns 技能,采用源自官方 Frappe 应用的应用外壳、导航、列表视图和表单布局。
  • 遵循命名约定:应用名称必须使用小写字母和下划线,并且是有效的 Python 标识符
  • 使用 hooks.py 进行集成:切勿猴子补丁;使用 doc_events、scheduler_events、boot_session 钩子
  • 保持 hooks.py 简洁:只放配置,不放逻辑;从模块导入
  • 保持向后兼容性:使用 frappe.version 检查以支持不同版本
  • 正确导出 fixtures:对于需要与应用同步的数据,在 hooks.py 中使用 fixtures

常见错误

错误失败原因修正方法
应用未加入 installed_apps应用代码未加载运行 bench --site <site> install-app my_app
hooks 中的模块路径错误事件不会触发确认路径与实际的 my_app/module/file.py 结构一致
重复注册钩子事件会触发多次检查 hooks.py 中是否存在重复项;使用列表,不要重复使用键
编辑 hooks.py 后未重启更改未生效修改 hooks.py 后运行 bench restart
缺少 __init__.py 文件模块导入错误确保每个目录都包含 __init__.py
在 hooks.py 中编写逻辑难以测试,且会出现导入错误将逻辑移至单独的模块,并在 hooks 中导入
使用原生 JS/jQuery 构建前端与生态系统不一致使用 Frappe UI(Vue 3);参阅 frappe-frontend-development
为 CRUD 应用自定义应用外壳用户体验不一致遵循 CRM/Helpdesk 的导航和布局模式

评论

支持 Markdown