ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Frappe Property Setter 详解:在运行时覆盖 DocType 与 DocField 标准属性

Frappe Property Setter 详解:在运行时覆盖 DocType 与 DocField 标准属性 Frappe Property Setter 详解在运行时覆盖 DocType 与 DocField 标准属性【免费下载链接】frappeLow code web framework for real world applications, in Python and Javascript项目地址: https://gitcode.com/GitHub_Trending/fr/frappeProperty Setter属性设置器是 Frappe 低代码框架中一个轻量却功能强大的自定义机制它允许 System Manager系统管理员在不修改任何标准代码的前提下覆盖标准 DocType、DocField 的属性配置例如字段是否隐藏、是否只读、是否出现在列表视图中从而按业务需求定制表单行为。读完本文你将掌握 Property Setter 的字段语义、命名规则、API 编程方式、运行时生效原理以及它与 Customize Form、Custom Field 的边界能够独立完成属性覆盖—验证—清理的完整闭环。一、Property Setter 是什么标准配置之上的覆盖层官方文档 frappe/custom/doctype/property_setter/README.md 对它的定位非常精炼Overrides standard DocType, DocField properties. The standard application is configured with properties for forms and fields (like, whether they are hidden or not). These can be overridden by a System Manager who can configure DocTypes based on custom requirements.翻译过来即Property Setter 覆盖标准 DocType、DocField 的属性。Frappe 标准应用为表单和字段配置了默认属性例如字段是否隐藏 hidden、是否只读 read_only、是否在列表视图中展示 in_list_view 等当默认配置不满足需求时System Manager 可以创建 Property Setter 记录来覆盖这些属性实现基于自定义需求的 DocType 配置。这段定位揭示了三个关键点贯穿本文始终它只覆盖不修改标准的 DocType 定义源码中的 JSON保持原样覆盖发生在运行时加载元数据Meta时见 frappe/model/meta.py 的apply_property_setters。权限集中在管理员角色只有Administrator与System Manager两个角色拥有完整读写权限见 property_setter.json。用途是定制化而非开发它解决的是标准应用不能满足的自定义需求属于配置层能力与写代码扩展 DocType 是两个层次。二、Property Setter 的字段语义与 DocType 定义Property Setter 本身也是一个 DocType其完整字段定义位于 frappe/custom/doctype/property_setter/property_setter.json。理解它的字段就理解了覆盖的四个维度作用对象Applied On→ 目标 DocType → 目标字段/行 → 要改的属性与值。2.1 核心定位字段字段名字段类型必填语义与取值范围doctype_or_fieldApplied OnSelect是覆盖作用的对象类型可选项为空、DocField、DocType、DocType Link、DocType Action、DocType State且一旦保存后即变为只读read_only_depends_on: eval:!doc.__islocaldoc_typeLink指向 DocType是被覆盖的 DocType 名称带搜索索引search_index: 1field_nameData否当doctype_or_field DocField时必填表示要覆盖的字段名row_nameData否用于DocType Link/DocType Action指定行记录的 namepropertyData是要覆盖的属性名例如hidden、read_only、in_list_view、fieldtype、reqd等property_typeData否属性的数据类型如Check、Data、Int运行时用于把value转型valueSmall Text否设置的新值对 Check 类型而言是0或1default_valueData否默认值moduleLinkModule Def否所属模块标注 Module (for export)用于随模块导出is_system_generatedCheck只读否是否为系统自动生成默认0is_app_disabledCheck只读否当所属 App 被禁用时置位默认02.2 字段间的依赖关系从 property_setter.json 的字段定义可以看到field_name通过depends_on: eval:doc.doctype_or_fieldDocField仅当作用对象为 DocField 时才显示/生效row_name的描述明确注明 For DocType Link / DocType Action表单顶部有一个 HTML 提示字段help内容是框架对使用者的明确警告Please dont update it as it can mess up your form. Use the Customize Form View and Custom Fields to set properties!请不要直接编辑它以免破坏表单请使用 Customize Form View 与 Custom Fields 来设置属性。这条警告非常重要Property Setter 记录通常不应手工逐条创建而是通过 Customize Form 界面或编程 API 生成详见后文。2.3 权限配置权限表property_setter.json只授予两个角色全部权限create/read/write/delete/email/print/report/shareAdministratorSystem Manager这印证了 README 中 can be overridden by a System Manager 的表述——属性覆盖是受控的系统级操作普通用户角色无权创建或修改。三、命名规则autoname 如何生成唯一标识每个 Property Setter 记录的名称name由 property_setter.py 中的autoname方法自动生成def autoname(self): self.name {doctype}-{field}-{property}.format( doctypeself.doc_type, fieldself.field_name or self.row_name or main, propertyself.property )即名称格式为{DocType}-{字段名或行名}-{属性}覆盖 DocField 属性时如ToDo-status-hidden未指定字段名时回退到row_name两者都没有则使用main例如覆盖 DocType 本身属性时形如ToDo-main-field_order。这种确定性命名带来一个直接后果同一个 (doc_type, field_name, property) 组合最多只能存在一条记录。框架正是利用这一点做去重——见下一节的 validate 逻辑。四、核心行为逻辑校验、去重与缓存清理4.1 validate字段类型变更限制 去重 缓存清理property_setter.py 中的validate方法在每次保存时执行三段逻辑def validate(self): self.validate_fieldtype_change() if self.is_new(): delete_property_setter(self.doc_type, self.property, self.field_name, self.row_name) frappe.clear_cache(doctypeself.doc_type)字段类型变更限制validate_fieldtype_change第53-55行当要覆盖的属性是fieldtype且目标字段为naming_series时直接抛错拒绝——not_allowed_fieldtype_change [naming_series]第8行。这是因为命名序列字段的类型与编号生成机制强耦合不允许被运行时覆盖。去重新建记录时先删除同(doc_type, property, field_name, row_name)的旧记录delete_property_setter保证同一属性只保留最新一条覆盖。缓存清理frappe.clear_cache(doctypeself.doc_type)使该 DocType 的元数据缓存失效确保新覆盖立即生效on_trash第50-51行在删除记录时同样清理缓存。4.2 on_update字段一致性校验第57-64行 的on_update在更新后调用validate_fields_for_doctype对被覆盖的 DocType 做整体字段校验例如校验字段引用、权限级别等防止属性覆盖破坏了 DocType 的合法性。但存在两个跳过场景补丁patch执行期间frappe.flags.in_patch调用方显式设置ignore_validate或validate_fields_for_doctype False。4.3 权限审计钩子第66-74行 的get_permission_log_options表明当覆盖的属性是ignore_user_permissions或permlevel二者直接影响权限行为时系统会记录权限变更日志其余属性变更不写权限日志。五、编程 APImake_property_setter 与删除函数除了在界面中操作Property Setter 主要价值之一在于可通过 Python API 在代码、补丁或控制台中批量创建与删除。5.1 创建make_property_setter模块级函数 make_property_setter 是创建 Property Setter 的标准入口def make_property_setter( doctype, fieldname, property, value, property_type, for_doctypeFalse, validate_fields_for_doctypeTrue, is_system_generatedTrue, ): property_setter frappe.get_doc({ doctype: Property Setter, doctype_or_field: (for_doctype and DocType) or DocField, doc_type: doctype, field_name: fieldname, property: property, value: value, property_type: property_type, is_system_generated: is_system_generated, }) property_setter.flags.ignore_permissions True property_setter.flags.validate_fields_for_doctype validate_fields_for_doctype property_setter.insert() return property_setter参数语义doctype目标 DocTypefieldname目标字段名覆盖 DocType 自身属性时可传入对应字段名property/value/property_type要覆盖的属性名、新值、属性数据类型for_doctypeFalse为True时作用对象为DocType否则为DocFieldvalidate_fields_for_doctypeTrue是否在插入后触发字段一致性校验is_system_generatedTrue标记为系统生成与人工在界面创建区分。值得注意的是函数头部的注释# WARNING: Ignores Permissions忽略权限检查并通过flags.ignore_permissions True显式跳过权限校验——这是为补丁脚本、迁移代码准备的接口。典型调用示例——把 ToDo 的 status 字段在列表视图中隐藏frappe.make_property_setter( ToDo, status, hidden, 1, Check )5.2 删除delete_property_setter 与 bulk_delete_property_settersdelete_property_setter 按doc_type必填、property/field_name/row_name可选的过滤器删除记录并最终经由_delete_property_setters第169-174行逐条get_doc(...).delete(ignore_permissionsTrue, forceTrue)执行带钩子的删除。bulk_delete_property_setters 则面向批量场景其 docstring 给出了明确的输入契约[ {doctype: ToDo, fieldname: status, property: hidden}, {doctype: ToDo, fieldname: status, property: read_only}, ]要点doctype与fieldname为必填内部映射到doc_type/field_name缺失时抛出 doctypeandfieldnameare required for deleting property setters.bypass_hooksTrue时走frappe.db.delete原始删除不触发文档钩子并统一清理相关 DocType 缓存默认False时走带钩子的逐条删除。5.3 测试验证集成测试 test_property_setter.py 完整覆盖了上述行为先通过frappe.make_property_setter为 ToDo 的 status 字段创建hidden与no_copy两条 Check 型覆盖验证记录确实存在再分别用bypass_hooksTrue和默认方式批量删除并断言记录消失。该测试同时验证了make_property_setter接收字典式参数{doctype: ..., fieldname: ..., property: ..., value: 1, property_type: Check}的重载用法批量删除对两种模式直删 / 走钩子均生效。六、运行时生效原理Meta 加载时的 apply_property_settersProperty Setter 之所以能覆盖而不修改标准定义核心在于 frappe/model/meta.py 的apply_property_setters方法——每次加载某 DocType 的元数据Meta时它都会把该 DocType 相关的 Property Setter 记录应用到内存中的元数据对象上。执行流程对应 第428-476行兜底检查若数据库尚无Property Setter表如全新安装早期阶段直接返回按 DocType 拉取frappe.db.get_values(Property Setter, filters{doc_type: self.name}, fieldname*)取全部相关记录过滤根据 App 禁用状态与模块禁用状态过滤记录——hide_disabled is_disabled_app_filtering_active()时排除is_app_disabled的记录同时排除is_module_disabled(ps.module)的模块记录按作用对象分发DocType→ 直接self.set(ps.property, cast(ps.property_type, ps.value))覆盖 DocType 自身属性DocField→ 在self.fields中按field_name找到字段对象并d.set(...)DocType Link/DocType Action/DocType State→ 分别在self.links/self.actions/self.states中按row_name记录的 name匹配后设置属性。cast(ps.property_type, ps.value)是关键一步value存的是字符串运行时根据property_type如Check、Int、Data转换为正确类型后再赋给属性。这正是 property_setter.json 中要求property_type字段的原因——它决定了值的转型方式。由于apply_property_setters在元数据构建链路上执行见 meta.py 第175行 的调用任何依赖 Meta 的模块表单渲染、列表视图、权限计算、字段校验都会自动感知覆盖结果这就是配置即可生效的底层原理。七、与 Customize Form、Custom Field 的分工与边界7.1 Customize FormProperty Setter 的前台frappe/custom/doctype/customize_form/customize_form.py 是 System Manager 在界面上修改 DocType/字段属性的入口它内部正是通过 Property Setter 持久化变更第299行删除旧的field_order覆盖第306行 与 第321行分别调用frappe.make_property_setter覆盖 DocType 级属性与 DocField 级属性第544-556行make_property_setter方法内部先delete_property_setter去重再插入。因此界面上的 Customize Form 操作最终落地为 Property Setter 记录。这也解释了 property_setter.json 中 help 字段的警告——普通用户应通过 Customize Form 操作而非直接编辑 Property Setter。7.2 Custom Field新增字段 vs 覆盖属性两者分工明确Custom Field用于给 DocType新增标准定义中不存在的字段Property Setter用于覆盖已有字段或 DocType 的既有属性如把已有字段设为隐藏、只读。需要改属性时用 Property Setter需要加字段时用 Custom Field二者互补且经常配合使用。7.3 模块导出与补丁Property Setter 的module字段标注 Module (for export)使其可以随模块导出/导入到其他环境同时它也是补丁patch机制中常用的配置迁移手段——补丁执行期间on_update会跳过字段校验frappe.flags.in_patch保证批量创建覆盖时不会因中间状态不完整而报错。八、最佳实践与注意事项综合源码行为给出如下实践建议优先使用 Customize Form 或编程 API避免手工逐条录入框架自身的 help 提示与去重逻辑都表明直接编辑 Property Setter 容易造成属性冲突或破坏表单。Check 类型属性的 value 只能是 0 或 1前端校验在 property_setter.js 中实现——frappe.ui.form.on(Property Setter, { validate: ... })会拦截非法值并提示 Value for a check field can be either 0 or 1。不要尝试修改naming_series的字段类型validate_fieldtype_change会拒绝此类变更。注意缓存Property Setter 的保存/删除都会clear_cache(doctype...)因此变更即时生效若绕过文档钩子直删bypass_hooksTrue需自行清理缓存bulk_delete_property_setters已内置该逻辑。善用批量删除接口清理自定义配置时用bulk_delete_property_setters按过滤器成批删除并可选择bypass_hooks提升性能。记录命名即幂等键由于名称由{doctype}-{field}-{property}决定重复创建同组合会先删旧后建新保证配置收敛。九、小结Property Setter 是 Frappe 自定义体系中最精炼的一环一条记录DocType、作用对象、字段/行、属性名、类型、值即可在运行时覆盖标准 DocType/DocField 的属性其命名规则保证幂等、缓存清理保证即时生效、编程 API 支持批量自动化、权限与字段校验保证安全边界。理解它就掌握了 Frappe零代码定制表单的底层实现也能更好地使用 Customize Form 界面与编写配置类补丁。相关源码与测试索引官方定位说明frappe/custom/doctype/property_setter/README.mdDocType 字段与权限定义frappe/custom/doctype/property_setter/property_setter.json核心逻辑autoname / validate / on_update / make_property_setter / 删除函数frappe/custom/doctype/property_setter/property_setter.py前端校验frappe/custom/doctype/property_setter/property_setter.js集成测试frappe/custom/doctype/property_setter/test_property_setter.py运行时应用覆盖frappe/model/meta.py#L428-L476Customize Form 集成frappe/custom/doctype/customize_form/customize_form.py【免费下载链接】frappeLow code web framework for real world applications, in Python and Javascript项目地址: https://gitcode.com/GitHub_Trending/fr/frappe创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表