视图设置
标题字段
DocType 中的一个字段,将作为表单中的标题显示
设置标题字段
在“标题字段”中输入自定义字段的名称
在链接字段中显示标题
您可以启用在链接字段中显示标题,以便在其他 DocType 的链接字段中显示标题,而不是名称。
因此,如果在另一个 DocType 中(或通过自定义表单)添加了“链接”类型的自定义字段,则该字段将显示链接文档的标题,而不是名称。
DocType 中的一个字段,将作为表单中的标题显示
设置标题字段
在“标题字段”中输入自定义字段的名称
在链接字段中显示标题
您可以启用在链接字段中显示标题,以便在其他 DocType 的链接字段中显示标题,而不是名称。
因此,如果在另一个 DocType 中(或通过自定义表单)添加了“链接”类型的自定义字段,则该字段将显示链接文档的标题,而不是名称。
控制器(Controller)是一个普通的 Python 类,它继承自 frappe.model.Document 基类。该基类是 DocType 的核心逻辑,负责处理值如何从数据库加载、如何解析以及如何保存回数据库。
当你创建一个名为 Person 的 DocType 时,系统会生成一个名为 person.py 的 Python 文件,其内容如下:
import frappe
from frappe.model.document import Document
class Person(Document):
pass
所有字段都可以作为类的属性来访问。
你可以向控制器添加自定义方法,并通过 doc 对象来调用它们。例如:
# controller class
class Person(Document):
def get_full_name(self):
"""Returns the person's full name"""
return f"{self.first_name} {self.last_name}"
# somewhere in your code
>>> doc = frappe.get_doc("Person", "000001")
>>> doc.get_full_name()
John Doe
为了在文档的生命周期中添加自定义行为,我们提供了控制器钩子。
| 方法名称 | 描述 | 插入 | 保存 | 提交 | 取消 | 提交后更新 |
|---|---|---|---|---|---|---|
before_insert |
在文档准备插入之前调用。 | X | ||||
before_naming |
在设置文档的 name 属性之前调用。 |
X | ||||
autoname |
如果在控制器中定义,此方法用于设置文档的 name 属性。 |
X | ||||
before_validate |
此钩子在验证之前调用,用于自动设置缺失的值。 | X | X | X | ||
validate |
使用此方法抛出任何验证错误并阻止文档保存。 | X | X | X | ||
before_save |
此方法在文档保存之前调用。 | X | X | |||
before_submit |
此方法在文档提交之前调用。 | X | X | |||
before_cancel |
此方法在文档取消之前调用。 | X | ||||
before_update_after_submit |
当已提交文档的字段被更新时调用此方法。 | X | ||||
db_insert |
此方法将文档插入数据库,除非你在处理虚拟 DocType,否则不要覆盖此方法。 | X | ||||
after_insert |
在文档插入数据库之后调用。 | X | ||||
db_update |
此方法更新数据库中的文档,除非你在处理虚拟 DocType,否则不要覆盖此方法。 | X | X | X | X | |
on_update |
当现有文档的值被更新时调用。 | X | X | X | ||
on_submit |
当文档被提交时调用。 | X | ||||
on_cancel |
当已提交的文档被取消时调用。 | X | ||||
on_update_after_submit |
当已提交文档的值被更新时调用。 | X | ||||
on_change |
当文档的值被更改时调用。此方法也会在 db_set 执行时被调用,因此在此方法中执行的操作应该是幂等的。 | X | X | X | X | X |
除了针对典型操作的文档事件外,你还可以挂钩到其他操作。
| 方法名称 | 描述 |
|---|---|
before_rename |
在文档重命名之前调用。 |
after_rename |
在文档重命名之后调用。 |
on_trash |
当文档被删除时调用。 |
after_delete |
在文档被删除之后调用。 |
要使用控制器钩子,只需定义一个具有该名称的类方法。例如:
class Person(Document):
def validate(self):
if self.age <= 18:
frappe.throw("Person's age must be at least 18")
def after_insert(self):
frappe.sendmail(recipients=[self.email], message="Thank you for registering!")
如果钩子不能满足你的需求,你也可以覆盖预定义的文档方法以添加你自己的行为。例如,要覆盖 save() 方法:
class Person(Document):
def save(self, *args, **kwargs):
super().save(*args, **kwargs) # call the base save method
do_something() # eg: trigger an API call or a Rotating File Logger that "User X has tried updating this particular record"
doc 对象默认提供了许多方法。你可以在这里找到完整的列表。
要创建新文档并将其保存到数据库:
doc = frappe.get_doc({
'doctype': 'Person',
'first_name': 'John',
'last_name': 'Doe'
})
doc.insert()
doc.name # 000001
要从数据库获取现有文档:
doc = frappe.get_doc('Person', '000001')
# doctype fields
doc.first_name # John
doc.last_name # Doe
# standard fields
doc.creation # datetime.datetime(2018, 9, 20, 12, 39, 34, 236801)
doc.owner # [email protected]
文档是 DocType 的一个实例。它通常映射到数据库表中的一行。在代码中我们称之为 doc。
示例
假设我们有一个名为 ToDo 的 DocType,包含以下字段:
descriptionstatuspriority现在,如果我们想从数据库中查询文档,可以使用 ORM。
>>> doc = frappe.get_doc("ToDo", "0000001")
<todo:>
>>> doc.as_dict()
{'name': '0000001',
'owner': 'Administrator',
'creation': datetime.datetime(2022, 3, 28, 18, 20, 23, 275229),
'modified': datetime.datetime(2022, 3, 28, 18, 20, 23, 275229),
'modified_by': 'Administrator',
'docstatus': 0,
'idx': 0,
'status': 'Open',
'priority': 'Medium',
'color': None,
'date': None,
'allocated_to': None,
'description': 'Test',
'reference_type': None,
'reference_name': None,
'role': None,
'assigned_by': 'Administrator',
'assigned_by_full_name': 'Administrator',
'sender': None,
'assignment_rule': None,
'doctype': 'ToDo'}
</todo:>
你可以获取 description、status 和 priority 的值,同时也会得到像 creation、owner 和 modified_by 这样的字段,这些字段是框架默认在所有 docs 上添加的。
在版本 15 中引入。
Frappe 支持在控制器文件中自动生成 Python 类型注解。这些注解可用于控制器文件中的自动补全、参考和类型检查。
class Person(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
first_name: DF.Data
last_name: DF.Data
user: DF.Link
# end: auto-generated types
pass
注意:这些注解在创建或更新文档类型时生成。如果你修改了代码块,它将在下次更新时被覆盖。
你可以通过添加以下钩子来配置应用中的自动导出。
# hooks.py
export_python_type_annotations = True
了解更多关于类型注解的信息:
DocField 定义了 DocType 的一个属性(或字段)。你可以为 DocField 定义列名、标签、数据类型等。例如,一个待办事项(ToDo)文档类型具有字段 description、status 和 priority。这些字段最终会成为数据库表 tabToDo 中的列。
示例
DocField 存储有关该字段的元数据。下面描述了其中的一些。
[
{
"label": "Description", // the value shown to the user (Form, Print, etc)
"fieldname": "description", // the property name we refer in code, also the column name
"fieldtype": "Text Editor", // the fieldtype which also decides how to store this value
"reqd": 1 // whether this field is mandatory
},
{
"label": "Status",
"fieldname": "status",
"fieldtype": "Select",
"options": [
"Open",
"Pending",
"Closed"
]
},
{
"label": "Priority",
"fieldname": "priority",
"fieldtype": "Select",
"options": [ // list of options for select
"Low",
"Medium",
"High"
],
"default": "Low" // the default value to be set
},
{
"label": "Completed By",
"fieldname": "completed_by",
"fieldtype": "Link",
"options": "User",
"depends_on": "eval: doc.status == 'Closed'", // the condition on which this field's display depends
},
{
"collapsible": 1,
"collapsible_depends_on": "eval:doc.status!='Closed'", // determines if a Section Break field is collapsible
"fieldname": "sb_details",
"fieldtype": "Section Break",
"label": "Details"
},
{
"fieldname": "amount",
"fieldtype": "Currency", // Currency field
"label": "Amount",
"non_negative": 1, // determines whether this field value can be negative
"options": "INR",
}
]
类似于 depends_on 属性(该属性决定字段是否显示),
在版本 12 中,我们引入了两个新属性:
mandatory_depends_on:如果满足此条件,该字段将成为必填项。read_only_depends_on:如果满足此条件,该字段将变为只读。Frappe 内置了超过 30 种不同的字段类型。
这些字段类型适用于各种使用场景。你可以在下一页了解更多关于字段类型的信息。
Frappe 中的所有 DocType 都有一个名为 name 的主键。这是您查找记录并使用 ORM 操作记录的唯一 ID。
您可以配置创建新文档时如何命名。框架中提供了 9 种命名方式:
文档名称由用户在创建时手动输入。
系统通过递增最后创建的文档来生成一个顺序数字名称。
关键注意事项:
1、2、3、4 的文档,并且您删除了 3,则下一个文档将被命名为 5,而不是 3。
自动递增
文档名称直接从特定字段的值中获取。
注意: 所选字段中的值必须始终是唯一的。
按字段名
命名模式来源于文档中的特定字段(通常是 naming_series)。
例如,如果您的文档中有一个字段 naming_series,并且其值设置为 PRE.#####,则将使用该模式来生成名称(例如,PRE00001)。此值可以根据文档而变化,允许同一 DocType 中的不同文档遵循不同的模式。
要求: 这仅在您的 DocType 中有一个名为
naming_series的字段时才有效。
按“命名系列”
您可以提供一个标准的命名模式,该模式将自动递增。
例如,如果您将模式设置为 PRE-.#####:
PRE-00001PRE-00002您可以使用此方法,通过多个字段值和变量灵活地配置命名方案。各个部分由点号 . 分隔。
示例模式:
EXAMPLE-.MM.-test-.{fieldname1}.-.{fieldname2}.-.#####
此格式允许您组合:
EXAMPLE、test)MM、YYYY、DD、WW、timestamp){fieldname1})#####)警告:在 v16 中弃用 此方法已弃用,并将在版本 16 中移除。
这是一种高度灵活的方法,可以使用多个字段值和变量配置命名方案。您可以直接在 DocType 设置中的 自动名称 字段中输入此模式。
示例模式:
EXAMPLE-{MM}-test-{fieldname1}-{fieldname2}-{#####}
此格式允许您组合:
EXAMPLE、test){MM}、{YYYY}、{DD}){fieldname1}){#####})生成一个随机的字母数字字符串作为文档名称。
随机
使用随机生成的通用唯一标识符(UUID v4)作为文档名称。
示例: 550e8400-e29b-41d4-a716-446655440000
UUID
您可以使用 DocType 的 Python 文件中的 autoname 控制器方法定义自定义命名逻辑。这使您可以完全控制命名过程。
from frappe.model.naming import getseries
class Project(Document):
def autoname(self):
# select a project name based on customer
prefix = f"P-{self.customer}"
series = getseries(prefix, 3)
self.name = f"{prefix}-{series}"
您还可以通过创建 文档命名规则 来为 DocType 创建命名规则。
您可以为特定 doctype 创建多个文档命名规则,这些规则可以根据筛选条件有选择地应用。
要定义文档命名规则,您必须指定:
您可以根据定义的条件为规则定义各种编号前缀。这是通过设置该规则的前缀和位数来完成的。
例如,如果您要为高优先级待办事项创建单独的编号:
将产生类似 todo-high-001、todo-high-002 等的编号。
当多个命名规则可能适用时,框架按以下顺序确定优先级:
autoname 属性中定义。autoname 方法中定义的逻辑(如果已定义,则覆盖 DocType 设置)。-1、-2 等)Frappe 框架中提供了多种字段类型。每种字段类型都有其特定的用途,可用于在文档中输入和存储不同类型的数据。字段类型用于在桌面端和 Web 表单中渲染组件。
数据字段是一个简单的文本字段。它允许您输入最多 140 个字符的值,是最通用的字段类型。
您可以为以下数据类型启用验证:
只需将选项分别设置为“姓名”、“电子邮件”、“电话”或“网址”即可。
将选项设置为“IBAN”可启用每 4 个字符一组的格式化显示。
链接字段连接到另一个主数据,并从中获取数据。例如,在报价单主数据中,客户是一个链接字段。要了解更多信息,请点击此处。
动态链接字段可以搜索并保存任何文档/文档类型的值。点击此处了解动态链接字段的工作原理。
这将使您能够在此处拥有一个复选框。您可以将 Default 值设置为 1,默认情况下它将被勾选。
使用“选择”字段类型,您可以创建一个下拉字段。您可以在选项字段中指定所有可选值,每个值用换行符分隔。
可以将其中一个可选值复制到默认值字段中。这样,在新表单中该值将默认被选中。
如果您启用选项排序复选框,则值将按字母顺序显示(以用户的语言显示)。
以下截图显示了如何在文档类型中或通过自定义表单定义“选择”字段:
这是它在新表单中的渲染效果:
使用“表格”字段,您可以将另一个文档类型作为子表渲染在您的表单中。
首先,您需要选择或定义一个启用了是子表复选框的文档类型。然后,您可以添加一个类型为“表格”的字段,并将子表文档类型的名称粘贴到选项字段中。
例如,ERPNext 定义了一个名为“采购收货项目”的子文档类型,并启用了是子表选项:
另一个名为“采购收货”的文档类型有一个类型为“表格”的字段,其选项设置为上述子文档类型“采购收货项目”:
最后,子表将渲染在采购收货表单中:
附件字段允许您从文件管理器中浏览文件并将其附加到此字段中。
附件画廊字段以响应式画廊的形式显示附加到当前文档的文件。图片显示为缩略图,可以打开以进行更大尺寸的预览。其他文件类型显示为文件卡片,并在新标签页中打开。
具有写入权限的用户可以直接从画廊上传和删除附件。启用只读将隐藏这些操作。必须先保存文档,然后才能上传文件。
默认情况下,画廊显示属于该文档的所有附件。使用过滤器来限制显示的文件记录。例如,仅显示 PDF 文件:
[["File", "file_type", "=", "PDF"]]
要仅显示通过特定画廊上传的文件,请使用该画廊的字段名称按 attached_to_field 进行过滤:
[["File", "attached_to_field", "=", "marketing_assets"]]
如果通过画廊上传的文件默认应为公开,请启用使附件公开(默认)选项。
附件图片是一种字段,允许您附加 jpeg、png 等格式的图片。该图片将成为代表该特定文档类型的图像。例如,如果您希望在项目文档类型中显示项目的图片,您可以将字段设置为附件图片字段。
文本编辑器是一个文本字段,渲染一个所见即所得的编辑器用于输入。它具有多种文本格式化选项。
此字段允许您在此字段中输入日期。
此字段将为您提供一个日期和时间选择器。默认设置为当前日期和时间(由您的计算机提供)。
在此字段中,您可以将字段指定为条形码,这将允许您输入条形码编号。完成后,系统将自动根据该编号生成条形码。
此字段用于在文档中放置一个按钮。它可用于执行特定操作,如发布博客文章、触发某个动作等。
此字段类型可用于接收 code 作为输入。文档表单中会渲染一个代码编辑器。可选地,您可以在字段类型选项中提供一种语言以启用语法高亮。例如,下面是一个 Code 类型的字段,其选项设置为 Python:
您可以通过设置“选项”来为以下语言启用基本的语法验证。
Python 和 PythonExpression 之间的差异示例:
variable = 42 是有效的 Python 代码,但不是有效的 PythonExpression,因为该赋值不会求值为任何值。variable == 42 既是有效的 Python 代码,也是有效的 PythonExpression,因为该表达式可以求值为某个值。这将允许用户通过渲染的颜色选择器输入颜色,或直接输入十六进制颜色代码。
这是一个 'meta' 字段类型,它不存储任何输入数据,但可用于在文档视图或表单中指示分栏。
例如,
将显示为:
货币字段保存数值,如项目价格、金额等。货币字段的值最多可包含六位小数。此外,您还可以为货币字段显示货币符号。
浮点数字段携带数值,最多可包含九位小数。
地理位置字段将显示一个地图视图,您可以在其上绘制多边形、线条和点。数据以 GeoJSON feature_collection 格式存储。
如果您添加一个字段名恰好为“location”的地理位置字段,您将获得一个额外的地图视图(相当于列表视图,但在地图上显示)。顺便说一下,如果您创建两个分别名为“latitude”和“longitude”的字段,这也同样有效。
注意:Frappe 使用“Leaflet”库,该库将坐标存储为 [纬度, 经度],这与 GeoJSON 通常的做法相反。
这会将 Options 中输入的内容作为 HTML 渲染在文档表单或视图页面中。以下是一个示例:
将显示为:
图像字段将渲染在另一个附件字段中选择的图像文件。
对于图像字段,应在“选项”(在 DocType 中)中提供一个字段名称,该字段中附加了图像文件。通过引用该字段中的值,图像将作为图像字段中的引用。
将显示为:
整数字段保存数值,没有小数位。
小文本字段携带文本内容,其字符限制比数据字段更大。
当您需要输入无字符限制的数据时,可以将字段定义为长文本字段。
此字段类型允许您在字段中添加文本。小文本、长文本和文本字段的字符限制将根据关系数据库管理系统来确定。
此字段允许您以 Markdown 格式添加文本。此字段类型还提供渲染后 HTML 的 Preview 视图:
当点击预览时:
密码字段将包含解码后的值。此类型的字段可用于存储敏感数据,如密码、口令、密钥等。
您可以将字段定义为百分比字段,在后台将按百分比进行计算。
此字段可用于显示交互式星级评分输入。默认显示的星数为 5,但是,您可以通过在该特定评分字段的选项字段中输入 3 到 10 之间的数字来轻松更改此设置。
您还可以提供半星评分,例如 3.5 分(满分 5 分)。
只读字段将携带从另一个表单获取的数据,这些数据不可编辑。如果其值的来源是预先确定的,您应将字段类型设置为只读。
分节符用于将表单划分为多个部分。任何跟在分节符字段之后(并且在任何其他 Section Break 之前)的字段都将属于这个新部分。
分页符用于将表单划分为多个选项卡。任何跟在分页符之后直到下一个 Tab Break 之前的字段都将属于这个新选项卡。
注意: 如果 DocType 的 fields 表不是以“页签分隔”开头的,系统将使用一个名为 Details 的默认页签分隔。这种情况仅在 DocType 的 fields 表中至少有一个 Tab Break 时才会发生。
您可以将字段定义为签名字段,在此字段中添加数字签名。阅读签名字段的文档以了解更多信息。
这是“链接”类型和“表格”类型字段的组合。与带有“添加行”按钮的子表不同,在一个字段中可以同时选择多个值。
这是一个时间字段,您可以在该字段中定义时间。
如果您想定义一个时间段,可以使用时长字段。
如果您不想以天或秒为单位跟踪时长,可以在表单中分别启用“隐藏天数”和“隐藏秒数”选项。一天等于24小时。
这将在您的数据库中创建一个 JSON 类型的列,并为桌面控件添加语法高亮功能。
虚拟文档字段(Virtual DocField)是给定文档(或记录)的一个动态属性。它是一个计算属性,不存储在站点数据库中。这可用于表示可能是其他静态文档属性函数的数值。
人员表单
一个人的年龄是其出生日期的函数,也就是说,如果你知道一个人的出生日期,就可以算出他的年龄。年龄也是一个连续值;它可能每年、每月、每天甚至每小时都在变化,具体取决于你想要的粒度。另一个属性是人的姓名。最常见的实现会有名字、中间名和姓氏,而在视图中,它们会组合在一起显示,如”Jon Raphael Doe”。虽然当字符串可以轻松拼接时,将全名保存为单独属性可能意义不大,但这些都是虚拟文档字段更合理的几个例子。
人员文档类型
在这里,我们向人员文档类型添加了三个字段:两个用于存储名字和姓氏(存储在站点数据库中),另一个利用这些数据来填充第三个字段”全名”。在此示例中,选项字段接收相应虚拟字段的返回值作为输入。
人员文档类型 – 文档字段
到目前为止,我们讨论了依赖于系统中属性的字段的可能性。但这可以轻松扩展到不仅仅依赖于你的文档类型数据的情况。你可能还想获取多个外部服务的状态,或者任何其他可以在此映射的内容。
实现此功能涉及的步骤如下:
定义虚拟文档字段相当简单。只需在文档字段的配置中勾选”虚拟”复选框即可。虚拟文档字段不会在文档类型的表中创建相应的列。这使得该字段在表单视图中为”只读”。
注意:除非你明确知道自己在做什么,否则避免将现有文档字段设为虚拟字段。
第一步只是为值添加了一个占位符。如果没有添加一些代码来指定字段应显示什么,字段本身就不存在。有两种方法可以实现这一点:
添加一个与虚拟字段同名的 Python 属性即可实现。这是最灵活的方法;你可以串联内部 API 请求,或从多个数据源获取数据,可能性是无限的。
class Person(Document):
@property
def age(self):
return frappe.utils.now_datetime() - self.creation
DocField.options这种方法限制稍多,因为它允许你直接从桌面端编写代码。服务器脚本中允许的实用程序和文档属性可以通过此方式访问。与上述属性等效的写法可能如下:
frappe.utils.now_datetime() - self.creation
上述提到的 Person.full_name 示例使用 Python 的 f-string 功能以类似方式实现。
注意:对于相对较小的脚本,应优先使用此方法。使用此方法时,请注意不兼容的类型错误。
如果你非常熟悉 Frappe 世界的运作原理,这个功能将会显得相当可预测。
DatabaseQuery 方法或 Database API 不会返回虚拟值,因为它们不存在于站点数据库中。
/api/method/frappe.desk.form.load.getdoc 和 /api/resource API 使用 Document.get_valid_dict,它也会计算虚拟值。这些 API 也用于渲染桌面端表单视图。
虚拟字段在相应文档类型的表中没有留下任何痕迹。但是,你可能会在存储文档类型元数据的自定义字段表、文档字段表中找到相应记录,以证明它们的存在。
注意:此功能仅在夜间版(v16)中可用。此功能被视为实验性功能。
虚拟子表是一种类型为”表”的虚拟字段,在运行时计算。它在许多方面与普通子表行为类似:
Document 实例。虚拟表对于显示计算/聚合数据或存储在其他位置的关联数据摘要非常有用。
要定义虚拟子表,你需要在父文档类型中添加一个新的字段条目,并将”is virtual”设置为 1。动态获取虚拟表的逻辑必须定义为文档类型控制器上的缓存属性。
注意:对于虚拟表,您不得使用 @property,仅支持 @cached_property 及其他等效的非数据描述符。
class User(…) :
# This is a cached_property (or a non-data descriptor) returning computed rows
@cached_property
def virtual_sessions(self):
# return a list of dicts or list of Document instances
sessions = get_session_logs(self.name)
return sessions
在此示例中,当加载 User 记录时,框架会调用 User.virtual_sessions 来获取子行,然后在表单上下文中初始化一个虚拟子表 virtual_sessions。
一个 DocType 总是归属于某个模块,以便于对相关模型进行分组管理。
Frappe 自带了许多内置模块。例如:
模块还有助于将代码文件按目录进行分组。由 DocType 生成的控制器文件
会存放在其对应的模块目录中。
frappe
├── commands
├── config
├── core
│ ├── doctype
│ │ ├── doctype
│ │ ├── docfield
│ │ ├── report
│ │ ├── system_settings
│ │ ├── ...
│ │ └── ...
│ ├── page
│ ├── report
│ └── web_form
├── desk
│ ├── doctype
│ │ ├── ...
│ │ ├── event
│ │ ├── kanban_board
│ │ ├── note
│ │ └── todo
│ ├── form
│ ├── page
Frappe 使用“文档状态”(Docstatus)的概念来跟踪交易的状态。文档状态始终为以下三个值之一:
不可提交的文档将始终保持在“草稿”状态。可提交的文档可以选择从草稿状态进入“已提交”状态,然后进入“已取消”状态。
处于已提交和已取消状态的文档无法编辑,但有一个例外:对于个别字段,我们可以明确允许编辑,即使文档处于已提交状态。
在后端代码中,我们有一个辅助类 DocStatus,可以按如下方式使用:
import frappe
from frappe.model.docstatus import DocStatus
draft_invoice_names = frappe.get_list(
"Sales Invoice",
filters={"docstatus": DocStatus.draft()},
pluck="name"
)
invoice_doc = frappe.get_doc("Sales Invoice", draft_invoice_names[0])
invoice_doc.docstatus == DocStatus.draft() # -> True
invoice_doc.docstatus.is_draft() # -> True
invoice_doc.docstatus.is_submitted() # -> False
invoice_doc.docstatus.is_cancelled() # -> False
invoice_doc.submit()
invoice_doc.docstatus == DocStatus.submitted() # -> True
invoice_doc.docstatus.is_draft() # -> False
invoice_doc.docstatus.is_submitted() # -> True
invoice_doc.docstatus.is_cancelled() # -> False
invoice_doc.cancel()
invoice_doc.docstatus == DocStatus.cancelled() # -> True
invoice_doc.docstatus.is_draft() # -> False
invoice_doc.docstatus.is_submitted() # -> False
invoice_doc.docstatus.is_cancelled() # -> True
文档状态以整数值的形式存储在数据库的每个 DocType 表中。
一个用于查看可提交文档类型在多个修订版本中所做更改的工具。当可提交文档被取消并修订时,由于文档名称发生变化,使用版本文档类型来跟踪文档更改会变得困难。审计追踪可用于查看可提交文档类型的最多 5 个先前修订版本。
更改的字段
不同版本中发生更改的字段值。
更新的行
不同版本中子表字段发生更改的值。
添加的行 / 删除的行
不同版本中每个子表添加或删除的行。
Frappe 站点可以共享同一个应用服务器,每个站点可以使用不同的数据库解决方案、配置和位置,并可通过 Bench 中的站点配置实现不同粒度的管理。
站点配置存储了所有与站点相关的信息,从站点的数据库详情到指向该站点的自定义域名。通过站点配置,我们可以定义可能改变 Frappe 和您的 Frappe 应用行为的键值对。
site_config.json 存储特定站点的全局配置,位于站点目录中。该文件由 Frappe 自动创建并填充。由于这依赖于 Frappe,默认设置或行为也可能因任何更新而改变。
{
"db_name": "frappe_database_name",
"db_password": "frappe_database_password",
"admin_password": "admin_password",
}
注意:此文件被视为包含与站点状态相关的重要信息,如果配置文件丢失或损坏,可能会带来麻烦。在标准设置中,它会与数据库备份一起定期备份。
common_site_config.json 存储您的 bench 共享的配置。在 Bench 级别执行的操作通常与此配置相关。定义的配置键可用于改变 bench 级别操作的行为,或影响您 bench 上的所有站点,具体取决于配置值的优先级。
此文件由 Bench CLI 自动生成和管理。此文件的更改可能会影响您的 Frappe 设置的行为,具体取决于您的系统设置和 Bench CLI 的版本。
{
"background_workers": 1,
"developer_mode": true,
"dns_multitenant": true,
"file_watcher_port": 6789,
"frappe_user": "frappe",
"gunicorn_workers": 2,
"maintenance_mode": 0,
"pause_scheduler": 0,
"redis_cache": "redis://localhost:13000",
"redis_cache_sentinel_enabled": 1,
"redis_cache_sentinels": [
"redis-cache-sentinel-1:26379",
"redis-cache-sentinel-2:26379"
],
"redis_cache_sentinel_password": "sentinelpassword",
"redis_cache_master_service": "mymaster",
"redis_cache_master_password": "masterpassword",
"redis_queue": "redis://localhost:11000",
"redis_queue_sentinel_enabled": 1,
"redis_queue_sentinels": [
"redis-queue-sentinel-1:26379",
"redis-queue-sentinel-2:26379"
],
"redis_queue_sentinel_password": "sentinelpassword",
"redis_queue_master_service": "mymaster",
"redis_queue_master_password": "masterpassword",
"redis_socketio": "redis://localhost:12000",
"scheduler_tick_interval": 120,
"serve_default_site": true,
"socketio_port": 9000,
"webserver_port": 8000,
"root_password": "MARIADB_PASSWORD",
"live_reload": true
}
workers |
允许创建自定义 worker。background_workers 参数是可选的,如果未设置,将使用通用的 background_workers。示例:"workers": { "custom_worker1": { "timeout": 5000, "background_workers": 4 } }。重新生成配置并重启进程以生效。 |
redis_cache_sentinel_enabled |
如果设置为 1,则在生产环境中连接到 Redis sentinel |
redis_cache_sentinels |
sentinel 服务器主机/ IP 和端口的数组 |
redis_cache_sentinel_password |
连接到 sentinel 的密码 |
redis_cache_master_service |
要连接的主服务 |
redis_cache_master_password |
Redis 主服务器密码 |
redis_queue_sentinel_enabled |
如果设置为 1,则在生产环境中连接到 Redis sentinel |
redis_queue_sentinels |
sentinel 服务器主机/ IP 和端口的数组 |
redis_queue_sentinel_password |
连接到 sentinel 的密码 |
redis_queue_master_service |
要连接的主服务 |
redis_queue_master_password |
Redis 主服务器密码 |
除此之外,您可以设置任何希望对所有站点可用的键。
在 site_config.json 中设置的特定键的值将优先于在 common_site_config.json 中定义的值。这意味着通用配置中定义的键值在某些情况下可以用作回退。
假设您想在 bench 上的所有站点上启用 Frappe Web Logger,但 worker.frappe.xyz 除外,因为假设它是一个高活动站点,您不需要同时被大量信息淹没。您可以在 common_site_config.json 中将 enable_frappe_logger 设置为 true,并在 worker.frappe.xyz 的 site_config.json 中将其设置为 false。
$ bench config set-common-config -c enable_frappe_logger true
$ bench --site worker.frappe.xyz set-config enable_frappe_logger false
类似地,可以有一个应用服务器来支持多个站点,每个站点使用不同的数据库解决方案提供商或位置。如果您选择将 bench 上的所有站点迁移到另一个数据库服务器,切换可能只需更新 bench 的 common_site_config.json 中的值即可。
这些是 Frappe Framework 和 Bench 使用的一些标准键。
这些键在 site_config.json 中设置,除非在站点创建期间提供了值,否则会自动生成。
db_type |
数据库类型。选项包括 “mariadb” 和 “postgres”。 |
db_name |
数据库名称(也用作默认数据库用户名)。 |
db_password |
数据库密码。 |
admin_password |
标准 “Administrator” 用户的默认密码。这将用作所有新站点的 Administrator 用户的密码。 |
allow_tests |
设置此项允许在此站点上运行测试。 |
allow_cors |
启用跨站点 HTTP 请求。可以设置为: – 特定来源,例如:"https://example.com" – 来源列表,例如:["https://portal.example.com", "https://shop.example.com"] – 通配符:"*"(不建议用于生产环境) |
allowed_referrers |
此处提到的域将允许绕过 CSRF,如果它们是请求的来源或引用者 |
backup_encryption_key |
用于加密/解密备份的密钥 |
data_import_batch_size |
数据导入的批量大小 |
db_user |
从 v16 开始,请指定单独的数据库用户名 |
deny_multiple_logins |
阻止用户拥有多个活动会话。 |
deny_multiple_sessions |
拒绝多个会话。 |
developer_mode |
如果设置了开发者模式,DocType 的更改会自动更新到文件中。 |
disable_async |
禁用 socket.io 客户端;客户端将停止轮询 socket.io 服务器。 |
disable_error_snapshot |
禁用错误快照。 |
disable_global_search |
禁用全局搜索。 |
disable_scheduler |
禁用调度器 |
disable_session_cache |
禁用会话缓存。 |
disable_website_cache |
禁用网站缓存。 |
encryption_key |
用于加密密码的密钥。此密码会在新站点上自动创建。在站点恢复时,也需要恢复此密钥才能使用现有密码。 |
enable_frappe_logger |
如果设置,将记录请求的基本信息并保存到 ./sites/{site}/logs/frappe.web.log 下。 |
error_report_email |
设置默认的错误报告电子邮件。 |
ignore_csrf |
忽略 CSRF。 |
install_apps |
在站点 restore、reinstall 和 new 创建时,列出要安装的应用。 |
host_name |
后台任务和打印需要此主机名来正确识别站点 URL。该值应包含协议和端口(如果不是默认端口),末尾不要带斜杠。例如:"https://erp.example.org:2424" |
http_port |
更改 Frappe 设置的 HTTP 端口。 |
keep_backups_for_hours |
在 frappe.utils.new_backup 中用于传递 frappe.utils.delete_temp_backups。它根据备份文件的年龄(以小时计)来保留备份文件。 |
local_infile |
设置标志以允许 MySQL 连接使用本地 infile 数据。 |
logging |
通过 frappe.log 使用 frappe.debug_log 来启用不同级别的日志记录。在级别 2,显示每次操作运行的查询和结果。 |
maintenance_mode |
启用维护模式。 |
max_file_size |
允许上传的最大文件大小。默认值为 10MiB。 |
max_reports_per_user |
用户可创建的最大自动邮件报告数量,默认为 3。 |
monitor |
如果设置,将记录所有请求并保存到 ./logs/monitor.json.log 下。请参阅调试文档中的监控部分。 |
mute_emails |
如果为 true,则停止发送电子邮件。 |
pause_scheduler |
暂停调度器 |
rate_limit |
使用 frappe.rate_limiter 指定速率限制。请参阅文档中的速率限制参考。 |
robots_txt |
访问 frappe-site.com/robots.txt 时要呈现的 robots.txt 文件路径 |
root_login |
数据库根用户名。 |
root_password |
数据库根密码。 |
server_script_enabled |
启用/禁用服务器脚本。 |
skip_setup_wizard |
跳过设置向导。 |
socketio_backend |
指定 Socket.IO 后端服务器实现。node (default) or python |
socketio_port |
指定 Socket.IO 端口。 |
webserver_port |
通常用作配置键 http_port 的回退。 |
app_include_js |
通过 URL 在 /app 中注入 JavaScript 脚本。必须是绝对 URL 的列表。 |
app_include_css |
通过 URL 在 /app 中注入 CSS 样式表。必须是绝对 URL 的列表。 |
disable_transaction_log |
禁用为销售发票和付款条目创建交易日志(ERPNext 区域功能)。 |
要使用 SSL 连接到远程数据库服务器,必须先配置数据库主机以接受 SSL 连接。有关如何执行此操作的示例,请参阅 Digital Ocean 的教程。完成配置后,设置以下三个选项。必须设置所有选项,Frappe 才会尝试使用 SSL 连接。
db_host |
数据库主机(如果不是 localhost)。 |
db_port |
指定数据库的端口。 |
db_ssl_ca |
用于通过 SSL 连接到数据库主机的 ca.pem 文件的完整路径。示例值为 "/etc/mysql/ssl/ca.pem"。 |
db_ssl_cert |
用于通过 SSL 连接到数据库主机的 cert.pem 文件的完整路径。示例值为 "/etc/mysql/ssl/client-cert.pem"。 |
db_ssl_key |
用于通过 SSL 连接到数据库主机的 key.pem 文件的完整路径。示例值为 "/etc/mysql/ssl/client-key.pem"。 |
rds_db |
在设置站点数据库时,授予某些特定权限而不是全部权限。在 db_manager.py 中使用。 |
在副本设置中,从辅助 MariaDB 服务器设置读取操作的指南可在用户指南中找到。
read_from_replica |
用于启用或禁用从副本读取。可接受的值为 1/0 或 true/false。 |
different_credentials_for_replica |
如果副本上的数据库凭据不同,则设置为 1,否则设置为 0 |
replica_host |
副本的 IP 地址 |
replica_db_name |
副本数据库名称 |
replica_db_password |
副本数据库密码 |
以下是 Frappe 邮件模块中一些可用的较低级别配置。
auto_email_id |
如果设置,这将是外发邮件的默认发件邮箱。 |
mail_login |
作为第二优先选项使用,”[email protected]” 作为备用选项。 |
always_use_account_email_id_as_sender |
使用账户邮箱 ID 作为发件人。 |
always_use_account_name_as_sender_name |
使用账户名称作为发件人名称 |
email_sender_name |
邮件发件人名称。 |
mail_server |
SMTP 服务器主机名。 |
mail_port |
SMTP 端口。 |
mail_login |
SMTP 服务器登录 ID。 |
mail_password |
SMTP 服务器密码。 |
pop_timeout |
POP 超时时间。 |
use_ssl |
通过 SSL 连接。 |
use_tls |
通过 TLS 连接。 |
这些配置由 Bench 命令行工具使用,并且可以通过公共站点配置为系统上的每个 bench 进行不同设置。
restart_supervisor_on_update |
在 bench 更新时重启 supervisord |
restart_systemd_on_update |
在 bench 更新时重启 systemd |
release_bench |
如果设置,当前 bench 将仅被视为执行发布的工具。 |
background_workers |
分配给处理后台作业的工作进程数量。 |
dns_multitenant |
如果设置,则为 Bench 开启 DNS 多租户功能。在生成 NGINX 配置时使用。 |
file_watcher_port |
文件监视器的端口号 |
frappe_user |
创建当前 Bench 的用户。 |
gunicorn_workers |
Gunicorn 工作进程数量。默认最小值为 2。 |
gunicorn_max_requests |
Gunicorn 工作进程重启前处理的请求数。默认值为 5000。 |
maintenance_mode |
如果设置,将使站点离线并停止所有后台进程和计划任务。在站点迁移和 bench 更新操作期间使用。 |
pause_scheduler |
如果设置,将暂停指定站点的调度器。 |
redis_cache |
Bench Procfile 中定义的 redis 缓存进程的端口号。 |
redis_queue |
Bench Procfile 中定义的 redis 队列进程的端口号。 |
redis_socketio |
Bench Procfile 中定义的 redis Socket.IO 进程的端口号。 |
scheduler_tick_interval |
作业调度器运行一个循环,每 scheduler_tick_interval 秒将所有待执行的计划任务加入队列。这使得可以设置调度作业的最小频率。默认为 60。 |
socketio_port |
Bench Procfile 中定义的 Socket.IO 进程的端口号。 |
webserver_port |
Frappe Web 服务器的端口号。 |
live_reload |
当资源重建时自动重新加载 Desk。 |
如果您是服务提供商,某些第三方集成可能需要您为 bench 上的所有站点定义较低级别的配置。Frappe 允许您通过站点配置为您的集成定义这些配置设置。
sandbox_api_key |
沙盒 API 密钥 |
sandbox_api_secret |
沙盒 API 密钥密码 |
sandbox_api_password |
沙盒 API 密码 |
sandbox_api_username |
沙盒 API 用户名 |
sandbox_publishable_key |
沙盒可发布密钥 |
sandbox_signature |
沙盒签名 |
dropbox_access_key |
Dropbox 访问密钥 |
dropbox_broker_site |
Dropbox 代理站点 |
dropbox_secret_key |
Dropbox 密钥密码 |
paypal_username |
PayPal 用户名 |
paypal_password |
PayPal 密码 |
paypal_signature |
PayPal 签名 |
google_analytics_id |
Google Analytics ID |
converted_rupee_to_paisa |
为 RazorPay 设置将卢比转换为派萨 |
有时,用户可能不希望将数据库密码等配置值直接硬编码在站点配置 JSON 中。在这种情况下,站点正常设置后,您可以安装一个自定义应用,该应用允许通过返回一个字典来扩展站点配置,字典中包含您希望追加或覆盖的任何值。该应用可以按任何所需方式获取这些值,但最好使用低延迟的方式,因为它需要在每次请求站点时运行。
可以按如下方式进行配置(在初始站点设置和安装应用后执行)
{
"extra_config": "vault.vault.conf_hook"
}
或者如果您有多个
{
"extra_config": ["vault.vault.conf_hook1", "vault.vault.conf_hook2"]
}
自定义应用中该方法的一个示例是
def conf_hook() -> dict:
password = get_password()
return {"db_password": password}
某些配置值可以通过环境变量进行覆盖。
优先级为:环境变量 -> 站点配置 -> 默认值(如果 Frappe 已配置了默认值)
| 配置 | 环境变量 |
redis_queue |
FRAPPE_REDIS_QUEUE |
redis_cache |
FRAPPE_REDIS_CACHE |
db_type |
FRAPPE_DB_TYPE |
db_socket |
FRAPPE_DB_SOCKET |
db_host |
FRAPPE_DB_HOST |
db_port |
FRAPPE_DB_PORT |
db_user |
FRAPPE_DB_USER |
db_name |
FRAPPE_DB_NAME |
db_password |
FRAPPE_DB_PASSWORD |