frappe-web-forms
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFrappe Web Forms
Frappe Web Forms
Build public-facing web forms for data collection, submissions, and customer self-service.
构建用于数据收集、信息提交和客户自助服务的面向公众的Web表单。
When to use
适用场景
- Creating forms for external users (no Desk access)
- Building support/ticket submission forms
- Collecting customer feedback or registrations
- Enabling self-service data entry portals
- Replacing simple portal pages with form-based workflows
- 为外部用户(无Desk权限)创建表单
- 构建支持/工单提交表单
- 收集客户反馈或注册信息
- 搭建自助数据录入门户
- 用基于表单的工作流替代简单的门户页面
Inputs required
所需输入
- Target DocType for form submissions
- Which fields to expose on the web form
- Authentication requirements (login required vs guest)
- Whether users can edit/resubmit entries
- File upload requirements
- 表单提交对应的目标DocType
- 要在Web表单上展示的字段
- 认证要求(是否需要登录 vs 访客访问)
- 用户是否可以编辑/重新提交条目
- 文件上传要求
Procedure
操作步骤
0) Prerequisites
0) 前提条件
Ensure the target DocType exists and has the fields you want to expose.
确保目标DocType已存在,且包含你想要展示的字段。
1) Create the Web Form
1) 创建Web表单
- Type "new web form" in the awesomebar
- Enter a Title (becomes the URL slug)
- Select the DocType for record creation
- Add introduction text (optional, shown above the form)
- Click "Get Fields" to import all fields, or add fields manually
- Set field order and which are required
- Publish the form
- 在awesomebar中输入“new web form”
- 输入标题(将作为URL路径别名)
- 选择用于创建记录的DocType
- 添加介绍文本(可选,显示在表单上方)
- 点击“Get Fields”导入所有字段,或手动添加字段
- 设置字段顺序和必填项
- 发布表单
2) Configure settings
2) 配置设置
| Setting | Purpose |
|---|---|
| Login Required | Require authentication before form access |
| Allow Edit | Let users edit their submitted entries |
| Allow Multiple | Let users submit more than one entry |
| Show as Card | Display in card layout style |
| Max Attachment Size | Limit file upload sizes |
| Success URL | Redirect after successful submission |
| Success Message | Custom message after submission |
| 设置项 | 用途 |
|---|---|
| Login Required | 要求用户先认证才能访问表单 |
| Allow Edit | 允许用户编辑已提交的条目 |
| Allow Multiple | 允许用户提交多条条目 |
| Show as Card | 以卡片布局样式显示 |
| Max Attachment Size | 限制文件上传大小 |
| Success URL | 提交成功后的跳转地址 |
| Success Message | 提交成功后的自定义提示信息 |
3) Make it a Standard Web Form (app-bundled)
3) 设为标准Web表单(应用捆绑)
Check "Is Standard" (visible in Developer Mode) to export the form as files:
my_app/
└── my_module/
└── web_form/
└── contact_us/
├── contact_us.json # Web form metadata
├── contact_us.py # Server-side customization
└── contact_us.js # Client-side customization勾选“Is Standard”(仅在开发者模式下可见),将表单导出为文件:
my_app/
└── my_module/
└── web_form/
└── contact_us/
├── contact_us.json # Web form metadata
├── contact_us.py # Server-side customization
└── contact_us.js # Client-side customization4) Add server-side customization
4) 添加后端自定义
python
undefinedpython
undefinedcontact_us.py
contact_us.py
import frappe
def get_context(context):
"""Add custom context variables to the web form."""
context.categories = frappe.get_all("Support Category",
filters={"enabled": 1},
fields=["name", "label"],
order_by="label asc"
)
def validate(doc):
"""Custom validation before the document is saved."""
if not doc.email:
frappe.throw("Email address is required")
# Prevent duplicate submissions
existing = frappe.db.exists("Support Ticket", {"email": doc.email, "status": "Open"})
if existing:
frappe.throw("You already have an open ticket. Please wait for a response.")undefinedimport frappe
def get_context(context):
"""Add custom context variables to the web form."""
context.categories = frappe.get_all("Support Category",
filters={"enabled": 1},
fields=["name", "label"],
order_by="label asc"
)
def validate(doc):
"""Custom validation before the document is saved."""
if not doc.email:
frappe.throw("Email address is required")
# Prevent duplicate submissions
existing = frappe.db.exists("Support Ticket", {"email": doc.email, "status": "Open"})
if existing:
frappe.throw("You already have an open ticket. Please wait for a response.")undefined5) Add client-side customization
5) 添加前端自定义
javascript
// contact_us.js
frappe.ready(function() {
// Handle field changes
frappe.web_form.on("field_change", function(field, value) {
if (field === "category" && value === "Urgent") {
frappe.web_form.set_df_property("description", "reqd", 1);
}
});
// Custom validation
frappe.web_form.validate = function() {
let data = frappe.web_form.get_values();
if (data.phone && !data.phone.match(/^\+?[0-9\-\s]+$/)) {
frappe.msgprint("Please enter a valid phone number");
return false;
}
return true;
};
// Custom after-save behavior
frappe.web_form.after_save = function() {
frappe.msgprint("Thank you for your submission!");
};
});javascript
// contact_us.js
frappe.ready(function() {
// Handle field changes
frappe.web_form.on("field_change", function(field, value) {
if (field === "category" && value === "Urgent") {
frappe.web_form.set_df_property("description", "reqd", 1);
}
});
// Custom validation
frappe.web_form.validate = function() {
let data = frappe.web_form.get_values();
if (data.phone && !data.phone.match(/^\+?[0-9\-\s]+$/)) {
frappe.msgprint("Please enter a valid phone number");
return false;
}
return true;
};
// Custom after-save behavior
frappe.web_form.after_save = function() {
frappe.msgprint("Thank you for your submission!");
};
});6) Control permissions
6) 权限控制
- Guest access: Uncheck "Login Required" for fully public forms
- Portal roles: Assign portal roles to control which logged-in users see the form
- User permissions: Set explicit document-level permissions on the target DocType
- Row-level access: Use User Permission rules to restrict which records users can edit
- 访客访问:取消勾选“Login Required”以设置完全公开的表单
- 门户角色:分配门户角色来控制哪些已登录用户可以看到该表单
- 用户权限:在目标DocType上设置明确的文档级权限
- 行级访问:使用用户权限规则限制用户可编辑的记录
7) Style the web form
7) 自定义Web表单样式
Web forms use the website theme by default. For custom styling:
html
<!-- Add custom CSS via Web Form → Custom CSS field -->
<style>
.web-form-container { max-width: 600px; margin: 0 auto; }
.web-form-container .form-group { margin-bottom: 1.5rem; }
.web-form-container .btn-primary { background-color: #2490EF; }
</style>Web表单默认使用网站主题。如需自定义样式:
html
<!-- Add custom CSS via Web Form → Custom CSS field -->
<style>
.web-form-container { max-width: 600px; margin: 0 auto; }
.web-form-container .form-group { margin-bottom: 1.5rem; }
.web-form-container .btn-primary { background-color: #2490EF; }
</style>Verification
验证步骤
- Web form accessible at the correct URL ()
/contact-us - All fields render correctly
- Required field validation works
- Submission creates the correct DocType record
- Login requirement enforced (if configured)
- Edit and resubmit work (if configured)
- File uploads work within size limits
- Success message/redirect works after submission
- Custom Python validation runs on submit
- Web表单可通过正确的URL访问(如)
/contact-us - 所有字段正确渲染
- 必填字段验证功能正常
- 提交操作可创建正确的DocType记录
- 登录要求已生效(若已配置)
- 编辑和重新提交功能正常(若已配置)
- 文件上传在大小限制内可正常工作
- 提交成功后的提示信息/跳转功能正常
- 自定义Python验证在提交时运行
Failure modes / debugging
故障模式与调试
- Form not accessible: Check if published; verify URL slug
- Permission denied on submit: Check DocType permissions for Website User or Guest
- Fields not showing: Ensure fields are added to the Web Form (not just on the DocType)
- Custom JS not loading: Check browser console; ensure file path is correct
- Validation not firing: Verify function in Python file returns/throws correctly
validate - Duplicate entries: Check "Allow Multiple" setting; add custom duplicate detection
- 表单无法访问:检查是否已发布;验证URL路径别名
- 提交时权限被拒绝:检查Website User或Guest角色的DocType权限
- 字段未显示:确保字段已添加到Web表单(而不仅仅是在DocType上)
- 自定义JS未加载:检查浏览器控制台;确保文件路径正确
- 验证未触发:验证Python文件中的函数是否正确返回/抛出异常
validate - 重复条目:检查“Allow Multiple”设置;添加自定义重复检测逻辑
Escalation
问题升级渠道
- For DocType schema →
frappe-doctype-development - For Frappe UI portal apps →
frappe-frontend-development - For API endpoint access →
frappe-api-development
- 关于DocType架构 →
frappe-doctype-development - 关于Frappe UI门户应用 →
frappe-frontend-development - 关于API端点访问 →
frappe-api-development
References
参考资料
- references/web-forms.md — Web Form creation and customization
- references/web-forms.md — Web表单创建与自定义
Guardrails
安全防护措施
- Validate input server-side: Never trust client validation; check in Python method
validate() - Use captcha for public forms: Enable reCAPTCHA for guest-accessible forms to prevent spam
- Sanitize output: Escape user-submitted data when displaying; use
frappe.utils.escape_html() - Limit file uploads: Set max file size and allowed types for attachment fields
- Check rate limits: Consider throttling form submissions from same IP
- 后端验证输入:永远不要信任客户端验证;在Python的方法中进行检查
validate() - 公共表单使用验证码:为访客可访问的表单启用reCAPTCHA以防止垃圾信息
- 清理输出内容:显示用户提交的数据时进行转义;使用
frappe.utils.escape_html() - 限制文件上传:为附件字段设置最大文件大小和允许的类型
- 检查速率限制:考虑对同一IP的表单提交进行限流
Common Mistakes
常见错误
| Mistake | Why It Fails | Fix |
|---|---|---|
| Missing DocType permissions | "Permission denied" on submit | Grant Create permission to Website User or Guest role |
| Not handling file uploads | Files don't attach to record | Configure Attach field properly; check upload limits |
| XSS vulnerabilities | Security risk | Escape user input in display; use ` |
| Forgetting to publish form | 404 error | Check "Published" checkbox in Web Form |
| Client-only validation | Invalid data in database | Add |
| Not testing as guest user | Works for admin, fails for users | Test in incognito/logged out mode |
| 错误 | 失败原因 | 修复方案 |
|---|---|---|
| 缺少DocType权限 | 提交时提示“Permission denied” | 为Website User或Guest角色授予创建权限 |
| 未处理文件上传 | 文件未附加到记录 | 正确配置Attach字段;检查上传限制 |
| XSS漏洞 | 安全风险 | 在显示时转义用户输入;在模板中使用` |
| 忘记发布表单 | 出现404错误 | 检查Web表单中的“Published”复选框 |
| 仅客户端验证 | 数据库中存在无效数据 | 在Web表单的Python文件中添加 |
| 未以访客用户身份测试 | 管理员可用,但普通用户无法使用 | 在隐身模式/注销状态下测试 |