控制器(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 对象默认提供了许多方法。你可以在这里找到完整的列表。
1. 创建文档
要创建新文档并将其保存到数据库:
doc = frappe.get_doc({
'doctype': 'Person',
'first_name': 'John',
'last_name': 'Doe'
})
doc.insert()
doc.name # 000001
2. 加载文档
要从数据库获取现有文档:
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]
文档(Document)
文档是 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
了解更多关于类型注解的信息:
- https://docs.python.org/3/library/typing.html
- VS Code 用户可以安装 Python 扩展以获得更好的自动补全功能 – https://code.visualstudio.com/docs/languages/python
- 大多数其他编辑器都有使用 LSP 的等效插件系统。