虚拟文档类型

虚拟 DocType 是 DocType 的一个功能扩展,允许开发者创建具有自定义数据源和 DocType 控制器的 DocType。其目的是在系统中定义自定义 DocType,而无需在数据库中创建表,同时利用框架提供的前端、资源 API 以及角色和权限功能。

这些虚拟 DocType 在前端的行为与普通 DocType 完全一致,对最终用户来说无法区分,但为开发者提供了对 DocType 数据源的更多控制。借助这一特性,虚拟 DocType 的数据源可以是任何内容:外部 API、辅助数据库、JSON 或 CSV 文件等。这使得开发者能够接入除 MariaDB 和 Postgres 之外的其他数据库后端,让 Frappe 框架变得更加强大!

注意:frappe.db.* 调用仅适用于站点数据库连接。您需要实现相应方法,以直接查询虚拟 DocType 所使用的数据存储。

创建虚拟 DocType

要创建虚拟 DocType,只需在创建 DocType 时勾选“虚拟 DocType”复选框即可:

创建自定义控制器

例如,以下控制器代码使用 JSON 文件作为 DocType 的数据源:

class VirtualDoctype(Document):
    """This is a virtual doctype controller for demo purposes.

 - It uses a single JSON file on disk as "backend".
 - Key is docname and value is the document itself.

 Example:
 {
 "doc1": {"name": "doc1", ...}
 "doc2": {"name": "doc2", ...}
 }
 """

    DATA_FILE = "data_file.json"

 @staticmethod
    def get_current_data() -> dict[str, dict]:
        """Read data from disk"""
        if not os.path.exists(VirtualDoctype.DATA_FILE):
            return {}

        with open(VirtualDoctype.DATA_FILE) as f:
            return json.load(f)

 @staticmethod
    def update_data(data: dict[str, dict]) -> None:
        """Flush updated data to disk"""
        with open(VirtualDoctype.DATA_FILE, "w+") as data_file:
            json.dump(data, data_file)

    def db_insert(self, *args, **kwargs):
        d = self.get_valid_dict(convert_dates_to_str=True)

        data = self.get_current_data()
        data[d.name] = d

        self.update_data(data)

    def load_from_db(self):
        data = self.get_current_data()
        d = data.get(self.name)
        super(Document, self).__init__(d)

    def db_update(self, *args, **kwargs):
        # For this example insert and update are same operation,
        # it might be different for you.
        self.db_insert(*args, **kwargs)

    def delete(self):
        data = self.get_current_data()
        data.pop(self.name, None)
        self.update_data(data)

 @staticmethod
    def get_list(args):
        data = VirtualDoctype.get_current_data()
        return [frappe._dict(doc) for name, doc in data.items()]

 @staticmethod
    def get_count(args):
        data = VirtualDoctype.get_current_data()
        return len(data)

 @staticmethod
    def get_stats(args):
        return {}

您可以在接口文件中了解接口要求及详细说明。要将其他数据源与虚拟 DocType 集成,您需要添加定义数据库访问方式的控制器方法。

结果

虚拟 DocType 的前端保持不变

框架定义的所有 /api/resource 方法均与虚拟 DocType 兼容。

自版本 13 起新增