脚本 API

在 Frappe 框架的服务器脚本、打印格式和脚本报表中可以调用的受限命令列表

注意: 这仅适用于应用内脚本。如果您需要更多功能,您必须创建一个“应用程序”并在 Python 模块中编写事件处理程序

Python 模块

以下 Python 模块可用

json

Python 标准模块 json

格式化

_(翻译)

翻译一个字符串

示例:_("This is translatable")

frappe.format

根据数据类型格式化一个值

示例:frappe.format_value(value, dict(fieldtype='Currency'))

frappe.date_format

格式化为默认日期格式

frappe.format_date

返回日期如“2019年9月1日”

会话

frappe.form_dict

表单/请求参数

示例:请求参数 /page?name="test" 可以通过 frappe.form_dict.name 访问

frappe.request

请求对象

frappe.response

响应对象

frappe.session.user

当前用户

frappe.session.csrf_token

当前会话的 CSRF 令牌

frappe.user

当前用户

frappe.get_fullname

返回当前用户的全名

frappe.get_gravatar

从 frappe.utils.get_gravatar_url 获取用户显示图像

frappe.full_name

当前用户的全名

文档(ORM)

文档访问和编辑

frappe.get_meta

获取元数据对象

frappe.new_doc

创建一个新的文档记录。

frappe.get_doc

获取文档。您还可以保存或执行文档公开的任何方法。

示例:frappe.get_doc("User", frappe.session.user)

frappe.get_last_doc

获取特定 DocType 的最后一条文档,可带有一组给定的过滤器。默认为最后创建的。

示例:frappe.get_last_doc("User", filters={"name": ("like", "%@apple.com")})

frappe.get_cached_doc

获取文档(或缓存的)

frappe.get_mapped_doc

frappe.rename_doc

frappe.delete_doc

frappe.get_system_settings

获取系统默认设置

数据库

数据库访问 API

frappe.db.get_list

获取由当前用户权限过滤的记录列表

示例:frappe.db.get_list("Customer") 将返回客户列表

frappe.db.get_all

获取所有记录的列表

frappe.db.sql

运行一个 SELECT 查询

示例:frappe.db.sql("select name from Customer where name like 'm%'")

frappe.db.get_value

从记录中获取一个值

示例:frappe.db.get_value("User", frappe.session.user, "first_name")

frappe.db.get_single_value

从单类型文档中获取值

示例:frappe.db.get_single_value("System Settings", "default_currency")

frappe.db.get_default

获取默认值

frappe.db.escape

清理数据库查询的值以防止 SQL 注入

frappe.db.set_value

设置一个值

frappe.db.exists

检查文档是否存在。如果存在则返回文档的 name,否则返回 None。

frappe.db.commit

允许用户在服务器脚本(如自定义调度器脚本)中进行显式提交。
注意:这在任何 DocType 事件服务器脚本中都不起作用

frappe.db.rollback

允许用户通过服务器脚本回滚更改。
注意:这在任何 DocType 事件服务器脚本中都不起作用

查询构建器

frappe.qb

用于运行 SELECT 查询的查询构建器 API。

示例:frappe.qb.from_("Task").select("*").run()

实用工具

实用方法和函数

run_script

运行一个服务器脚本(返回值在 frappe.flags 中)

frappe.msgprint

在服务器端作为响应的一部分显示一个模态框。

示例:frappe.msgprint("Hello")

frappe.get_hooks

获取应用程序钩子

frappe.utils

frappe.utils 中的方法

frappe.render_template

渲染一个 Jinja 模板

frappe.get_url

通过 frappe.utils.get_url 获取当前站点的 URL

socketio_port

socketio 的端口

style.border_color

返回 ‘#d1d8dd’

guess_mimetype

返回 mimetypes.guess_type

html2text

将 HTML 编码为文本(markdown)

dev_server

如果处于开发者模式则为 True

frappe.log_error

生成带有回溯的错误日志

FrappeClient

使用 requests 会话连接到 Frappe 站点

API

从 Frappe 发起外部 API 调用。

frappe.make_get_request

发起一个 GET 请求。

示例:frappe.make_get_request('https://example.com')

frappe.make_post_request

发起一个 POST 请求。

示例:frappe.make_post_request('https://example.com', data={'username: 'test'})

frappe.make_put_request

发起一个 PUT 请求。

示例:frappe.make_put_request('https://example.com', headers={'Auth': 'Bearer xyz'})

邮件

frappe.sendmail

发送一封邮件。请参阅文档

示例:frappe.sendmail(recipients=['[email protected]'], sender='[email protected]', subject='My Subject', message='<p>Hello</p>')

服务器脚本

注意:从版本 15 开始,服务器脚本默认被禁用,以提高共享 bench 的安全性。

你可以使用以下命令在你的 bench 上启用它们。

bench set-config -g server_script_enabled 1

如果你托管在 Frappe Cloud 上,你需要创建一个私有 bench 才能启用服务器脚本。公共共享 bench 不允许使用服务器脚本。

服务器脚本让你可以动态定义一个 Python 脚本,在文档事件或 API 触发时在服务器上执行。

如何创建服务器脚本


要创建服务器脚本

  1. 如果你的站点托管在 frappe cloud 上,这里有一篇帮助文章说明了启用服务器脚本的步骤。如果是自托管账户,请在你的站点的 site_config.json 中将 server_script_enabled 设置为 true。
  2. 要添加/编辑服务器脚本,请确保你的角色是系统管理员。
  3. 在 awesomebar 中输入“新建服务器脚本”并按回车,创建一个新的服务器脚本文档。
  4. 设置服务器脚本的类型(文档事件 / API)。
  5. 设置文档类型和事件名称,或方法名称、脚本并保存。
  6. 功能

2.1 启用服务器脚本

服务器脚本必须通过 site_config.json 启用

bench --site site1.local set-config server_script_enabled true

2.2 文档事件

对于要通过文档事件调用的脚本,你必须设置参考文档类型和事件名称来定义触发器

  • 插入前
  • 插入后
  • 验证前
  • 保存前
  • 保存后
  • 提交前
  • 提交后
  • 取消前
  • 取消后
  • 删除前
  • 删除后
  • 保存前(已提交文档)
  • 保存后(已提交文档)
  • 打印前

2.3 API 脚本

通过使用脚本类型 "API",可以即时创建 API 端点。端点的名称取决于API 方法字段。所有使用服务器脚本创建的 API 都会自动加上 /api/method 前缀。

例如,一个API 方法为 "delete-note" 的脚本可以通过 /api/method/delete-note 访问。使用 Frappe 的前端请求库,你可以在客户端脚本中使用 frappe.call("delete-note")。

可以通过为创建的 API 勾选允许访客来启用访客访问。响应可以通过 frappe.response["message"] 对象设置。

API 服务器脚本还支持基于 IP 的速率限制,你可以通过勾选“启用速率限制”并指定在给定时间窗口内可以进行多少次调用来启用它。

2.3 安全性

Frappe 框架使用 RestrictedPython 库来限制对服务器脚本可用方法的访问。只有下面列出的安全方法在服务器脚本中可用。

有关允许的方法,请参阅脚本 API

2.4 将服务器脚本用作库

你可以通过在脚本中设置 frappe.flags 值,将服务器脚本用作内部方法。

2.5 比较更改

你可以使用“比较版本”按钮来对比服务器脚本的两个版本。

示例


3.1 在更改前更改属性的值

脚本类型:保存前

if "test" in doc.description:
    doc.status = 'Closed'

3.2 自定义验证

脚本类型:“保存前”

if "validate" in doc.description:
    raise frappe.ValidationError

3.3. 自动创建待办事项

脚本类型:“保存后”

if doc.allocted_to:
    frappe.get_doc(dict(
        doctype = 'ToDo',
        owner = doc.allocated_to,
        description = doc.subject
    )).insert()

3.4 API

  • 脚本类型:API
  • 方法名称:test_method
frappe.response['message'] = "hello"

请求:/api/method/test_method

3.5 内部库

版本 13 中的新功能

从一个 script_1 脚本调用另一个 script_2

脚本 1:

frappe.flags.my_key = 'my value'

脚本 2:

my_key = run_script('script_1').get('my_key')

系统控制台

系统控制台可帮助您基于脚本 API 运行 Python 命令进行调试
。仅允许具有系统管理员角色的用户使用。

要访问系统控制台,请在搜索栏中搜索它。

API

脚本 API
公开的方法可以通过系统控制台访问

记录响应

要打印响应,请使用 log 方法。

客户端脚本

客户端脚本让你可以动态定义一个自定义表单脚本,该脚本会在用户的浏览器上执行。如果你选择使用非标准工具或库,请务必在不同浏览器上进行测试,以确保在你的用户群体中具备兼容性。

在版本 13 中,自定义脚本已重命名为客户端脚本

  1. 如何创建客户端脚本

创建客户端脚本的方法

  1. 要添加/编辑客户端脚本,请确保你的角色是系统管理员。

  2. 在搜索栏中输入“新建客户端脚本”并按回车,创建一个新的客户端脚本文档。

  3. 选择你想要自定义表单的文档类型。

  4. 使用预设模板更新脚本并保存。

  5. 前往你已自定义的文档类型,查看更改效果。

  6. 功能特性


与服务器脚本的诸多限制相比,客户端脚本中一切皆可自由使用。这是因为前端 API 在设计上就是安全的。你可以使用所有 JavaScript API,以及 Frappe 的 API 和你可能已用于自定义 Desk 的任何其他 JS 或 CSS 库。

你通过客户端脚本添加的验证只会在通过浏览器访问的标准表单视图中生效。如果你希望这些验证也能通过 API 或系统控制台访问时生效,请使用服务器脚本。

  1. 示例

3.1 自定义验证

在通过 Frappe 标准表单视图创建或更新文档时,添加额外的表单验证。

// additional validation on Task dates
frappe.ui.form.on('Task', 'validate', function(frm) {
    if (frm.doc.from_date < get_today()) {
        msgprint('You can not select past date in From Date');
    }
});

3.2 在字段更新时获取值

在更改 customer 字段的值时获取 local_tax_no。

cur_frm.add_fetch('customer', 'local_tax_no', 'local_tax_no');

3.3 自定义字段属性

在创建文档后将字段 ibsn 设为只读。

// make a field read-only after saving
frappe.ui.form.on('Task',  {
    refresh: function(frm) {
        frm.set_df_property('ibsn', 'read_only', !frm.is_new());
    }
});

3.4 自定义字段属性

在保存时计算销售发票表单上的佣金。

// calculate sales incentive
frappe.ui.form.on('Sales Invoice',  {
    validate: function(frm) {
        // calculate incentives for each person on the deal
        total_incentive = 0
        $.each(frm.doc.sales_team,  function(i,  d) {
            // calculate incentive
            let incentive_percent = 2;
            if(frm.doc.base_grand_total > 400) incentive_percent = 4;
            // actual incentive
            d.incentives = flt(frm.doc.base_grand_total) * incentive_percent / 100;
            total_incentive += flt(d.incentives)
        });
        frm.doc.total_incentive = total_incentive;
    }
});

3.5 筛选邮件收件人

你可以通过客户端脚本限制可用的邮件地址。每个表单都可以指定哪些电子邮件地址应该可供选择。这可以减少用户的认知负担,并避免将邮件发送给错误的收件人。

CommunicationComposer(邮件对话框)会检查是否存在为“收件人”、“抄送”和“密送”字段提供筛选条件的客户端脚本。例如,如果某个报价单只应显示与该报价单收件人关联的电子邮件地址,我们可以添加以下脚本:

frappe.ui.form.on("Quotation", {
    get_email_recipient_filters: function (frm, field) {
        // field can be "recipients", "cc" or "bcc"
        if (field === "recipients") {
            return [
                [
                    "Dynamic Link",
                    "link_doctype",
                    "=",
                    frm.doc.quotation_to
                ],
                [
                    "Dynamic Link",
                    "link_name",
                    "=",
                    frm.doc.party_name
                ],
            ];
        }
    },
    // ...
};

这些筛选条件引用的是联系人文档类型及其链接子表。

即使有筛选条件,仍然可以粘贴任意收件人。

3.6 设置默认邮件收件人

在诸如销售订单 -> 交货单 -> 销售发票这样的标准流程中,邮件收件人通常是预先定义好的。例如,这可以由客户经理提前完成。

你可以通过客户端脚本设置默认邮件收件人。每个表单都可以通过编程方式提供自己的默认收件人。

CommunicationComposer(邮件对话框)会检查是否存在提供默认收件人的客户端脚本。例如,如果你的报价单文档类型包含一个名为密送("custom_bcc")的字段,你可以添加以下客户端脚本,将其用作邮件对话框中的默认密送地址:

frappe.ui.form.on("Quotation", {
    get_email_recipients: function (frm, field) {
        // field can be "recipients", "cc" or "bcc"
        if (field === "bcc") {
            return [frm.doc.custom_bcc]
        }
    },
    // ...
};