编写插件

你可以编写只应用于一个 Datasette 实例的一次性插件,也可以编写可以使用 pip 安装并发布到 Python 包索引 (PyPI) 供其他人安装的插件。

想从一个例子开始吗?Datasette 插件目录列出了 90 多个开源插件,你可以探索其代码。插件钩子页面包含了每个已文档化钩子的示例插件链接。

编写一次性插件

开始编写插件最快的方式是创建一个 my_plugin.py 文件并将其放入你的 plugins/ 目录。这里有一个示例插件,它添加了一个新的自定义 SQL 函数,名为 hello_world(),该函数不接受任何参数并返回字符串 Hello world!

from datasette import hookimpl


@hookimpl
def prepare_connection(conn):
    conn.create_function(
        "hello_world", 0, lambda: "Hello world!"
    )

如果你将其保存在 plugins/my_plugin.py 中,你可以这样启动 Datasette

datasette serve mydb.db --plugins-dir=plugins/

现在你可以导航到 http://localhost:8001/mydb 并运行此 SQL

select hello_world();

以查看你的插件输出。

使用 cookiecutter 启动可安装插件

可安装的插件应使用 setup.py 文件编写为 Python 包。

开始编写可安装插件的最快方式是使用 datasette-plugin cookiecutter 模板。这会为你创建一个全新的插件结构,包含示例测试和用于测试及发布插件的 GitHub Actions 工作流程。

安装 cookiecutter,然后运行此命令以使用模板开始构建插件

cookiecutter gh:simonw/datasette-plugin

阅读 用于编写 Datasette 插件的 cookiecutter 模板 以获取有关此模板的更多信息。

打包插件

插件可以使用 Python setuptools 进行打包。你可以在 https://github.com/simonw/datasette-plugin-demos 查看打包插件的示例。

该示例包含两个文件:一个定义插件的 setup.py 文件

from setuptools import setup

VERSION = "0.1"

setup(
    name="datasette-plugin-demos",
    description="Examples of plugins for Datasette",
    author="Simon Willison",
    url="https://github.com/simonw/datasette-plugin-demos",
    license="Apache License, Version 2.0",
    version=VERSION,
    py_modules=["datasette_plugin_demos"],
    entry_points={
        "datasette": [
            "plugin_demos = datasette_plugin_demos"
        ]
    },
    install_requires=["datasette"],
)

以及一个实现插件的 Python 模块文件 datasette_plugin_demos.py

from datasette import hookimpl
import random


@hookimpl
def prepare_jinja2_environment(env):
    env.filters["uppercase"] = lambda u: u.upper()


@hookimpl
def prepare_connection(conn):
    conn.create_function(
        "random_integer", 2, random.randint
    )

以这种方式构建插件后,你可以使用以下命令将其转换为可安装的包

python3 setup.py sdist

这将在 dist/ 目录下创建一个 .tar.gz 文件。

然后你可以使用 pip 将你的新插件安装到 Datasette 虚拟环境或 Docker 容器中

pip install datasette-plugin-demos-0.1.tar.gz

要了解如何将你的插件上传到 PyPI 供其他人使用,请阅读 PyPA 关于打包和分发项目的指南。

静态资源

如果你的插件有一个 static/ 目录,Datasette 将自动配置自己从以下路径提供这些静态资源

/-/static-plugins/NAME_OF_PLUGIN_PACKAGE/yourfile.js

使用 datasette.urls.static_plugins(plugin_name, path) 方法生成考虑了 base_url 设置的该资源的 URL,详见 datasette.urls

要在你发布到 PyPI 的包中捆绑插件的静态资源,请将以下内容添加到插件的 setup.py

package_data = (
    {
        "datasette_plugin_name": [
            "static/plugin.js",
        ],
    },
)

其中 datasette_plugin_name 是插件包的名称(注意使用下划线而不是连字符),static/plugin.js 是该包内静态文件的路径。

datasette-cluster-map 是一个有用的示例插件,它以这种方式包含了打包的静态资源。

自定义模板

如果你的插件有一个 templates/ 目录,Datasette 将会尝试先从该目录加载模板,然后才使用其默认模板。

模板加载的优先级顺序是

  • 来自 --template-dir 参数指定的模板(如果指定)

  • 来自任何已安装插件中 templates/ 目录的模板

  • Datasette 附带的默认模板

有关如何编写自定义模板的更多详细信息,包括使用哪些文件名来定制 Datasette UI 的哪些部分,请参阅自定义页面和模板

模板应使用上面为静态资源描述的 setup.py 中的相同 package_data 机制进行捆绑分发,例如

package_data = (
    {
        "datasette_plugin_name": [
            "templates/my_template.html",
        ],
    },
)

你还可以在此处使用通配符,例如 templates/*.html。有关此模式的示例,请参阅 datasette-edit-schema

编写接受配置的插件

在编写插件时,你可以使用 datasette plugin_config() 方法像这样访问插件配置。如果你知道需要特定表的插件配置,可以这样访问

plugin_config = datasette.plugin_config(
    "datasette-cluster-map", database="sf-trees", table="Street_Tree_List"
)

在上面的示例中,这将返回 {"latitude_column": "lat", "longitude_column": "lng"}

如果该插件没有配置,该方法将返回 None

如果它在表层找不到所需的配置,它将回退到数据库层,然后再回退到根层。例如,用户可能已像这样设置了插件配置选项

{
    "databases: {
        "sf-trees": {
            "plugins": {
                "datasette-cluster-map": {
                    "latitude_column": "xlat",
                    "longitude_column": "xlng"
                }
            }
        }
    }
}

在这种情况下,上面的代码将为 sf-trees 数据库中的任何表返回该配置。

插件配置也可以在 metadata.json 的顶层设置

{
    "title": "This is the top-level title in metadata.json",
    "plugins": {
        "datasette-cluster-map": {
            "latitude_column": "xlat",
            "longitude_column": "xlng"
        }
    }
}

现在 datasette-cluster-map 插件配置将应用于每个数据库中的每个表。

为你的插件设计 URL

你可以使用 register_routes(datasette) 插件钩子在 Datasette 中注册新的 URL 路由。

Datasette 的默认 URL 包括这些

  • /dbname - 数据库页面

  • /dbname/tablename - 表页面

  • /dbname/tablename/pk - 行页面

有关更多默认 URL 路由,请参阅页面和 API 端点以及自省

为避免意外与可能加载到 Datasette 的数据库文件冲突,插件应使用 /-/ 前缀注册 URL。例如,如果你的插件添加了一个新的 Excel 文件上传界面,你可能会注册一个像这样的 URL 路由

  • /-/upload-excel

尽量避免注册与用户可能已安装的其他插件冲突的 URL。目前还没有保留 URL 路径的中央仓库,但你可以通过浏览 插件目录 <https://datasette.com.cn/plugins> 来查看现有插件。

如果你的插件包含与特定数据库相关的功能,你也可以注册一个像这样的 URL 路由

  • /dbname/-/upload-excel

或者对于特定表,像这样

  • /dbname/tablename/-/modify-table-schema

请注意,行的主键可能是 -,并且此 URL 方案仍然有效,因为 Datasette 行页面后面永远不会有斜杠后跟额外的路径组成部分。

在插件内部构建 URL

定义自己的自定义用户界面元素的插件可能需要链接到 Datasette 中的其他页面。

如果 Datasette 实例使用 base_url 配置设置在代理后面运行,这可能会有点棘手,因为它可能导致 Datasette 的 URL 包含额外的路径前缀。

datasette.urls 对象提供了内部方法,用于正确生成指向 Datasette 中不同页面的 URL,同时考虑任何 base_url 配置。

此对象在模板中作为 urls 变量公开,可以这样使用

Back to the <a href="{{ urls.instance() }}">Homepage</a>

有关此对象的完整详细信息,请参阅datasette.urls