控制器

控制器(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,包含以下字段:

  • description
  • status
  • priority

现在,如果我们想从数据库中查询文档,可以使用 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:>

你可以获取 descriptionstatuspriority 的值,同时也会得到像 creationownermodified_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 的等效插件系统。