datasette-insert 作者 simonw

收藏

README 源代码

datasette-insert

PyPI Changelog License

用于插入和更新数据的 Datasette 插件

Datasette 1.0 后不再需要此插件。请改用JSON 写入 API

安装

在 Datasette 所在的同一环境中安装此插件。

$ pip install datasette-insert

部署此插件时应始终配置额外设置,以防止未经身份验证的访问,详见下文说明。

如果您是在自己的本地机器上试用,可以 pip install datasette-insert-unsafe 插件,以允许访问而无需单独设置身份验证或权限。

插入数据和创建表

启动 datasette 并确保已附加可写的 SQLite 数据库。如果您尚未创建数据库文件,可以使用此命令:

datasette data.db --create

如果 data.db 数据库文件不存在,--create 选项将创建一个新的空文件。

该插件添加了一个端点,允许通过向以下 URL POST JSON 数据来插入或更新数据以及创建表:

/-/insert/name-of-database/name-of-table

JSON 数据应如下所示:

[
    {
        "id": 1,
        "name": "Cleopaws",
        "age": 5
    },
    {
        "id": 2,
        "name": "Pancakes",
        "age": 5
    }
]

首次向该 URL POST 数据时,如果同名表尚不存在,将创建一个包含所需列的表。

您可以使用 ?pk= URL 参数指定哪个列用作主键。

以下是使用 Python requests 库向数据库 POST 数据并创建新表的示例:

import requests

requests.post("http://localhost:8001/-/insert/data/dogs?pk=id", json=[
    {
        "id": 1,
        "name": "Cleopaws",
        "age": 5
    },
    {
        "id": 2,
        "name": "Pancakes",
        "age": 4
    }
])

以下是使用 curl 执行相同操作的方法:

curl --request POST \
  --data '[
      {
        "id": 1,
        "name": "Cleopaws",
        "age": 5
      },
      {
        "id": 2,
        "name": "Pancakes",
        "age": 4
      }
    ]' \
    'http://localhost:8001/-/insert/data/dogs?pk=id'

或者通过管道输入 JSON,如下所示:

cat dogs.json | curl --request POST -d @- \
    'http://localhost:8001/-/insert/data/dogs?pk=id'

插入单行数据

如果您要插入单行数据,可以选择将其作为字典发送,而不是包含单个项目的列表。

curl --request POST \
  --data '{
      "id": 1,
      "name": "Cleopaws",
      "age": 5
    }' \
    'http://localhost:8001/-/insert/data/dogs?pk=id'

自动添加新列

如果您向现有表发送数据时,键与现有列不对应,您将收到一个 HTTP 400 错误,并附带如下所示的 JSON 响应:

{
    "status": 400,
    "error": "Unknown keys: 'foo'",
    "error_code": "unknown_keys"
}

如果您向 POST 的 URL 添加 ?alter=1,任何缺失的列将被自动添加。

curl --request POST \
  --data '[
      {
        "id": 3,
        "name": "Boris",
        "age": 1,
        "breed": "Husky"
      }
    ]' \
    'http://localhost:8001/-/insert/data/dogs?alter=1'

执行 Upsert 操作

"upsert" 操作可用于部分更新记录。通过 upsert,您可以发送键的子集,如果 ID 与指定的主键匹配,这些键值将被用于更新现有记录。

Upsert 操作可以发送到 /-/upsert API 端点。

此示例将把 ID=1 的狗的年龄从 5 更新为 7。

curl --request POST \
  --data '{
      "id": 1,
      "age": 7
    }' \
    'http://localhost:3322/-/upsert/data/dogs?pk=id'

/-/insert 端点类似,/-/upsert 端点也可以接受对象数组。它同样支持 ?alter=1 选项。

权限和身份验证

此插件默认拒绝所有访问,以帮助确保人们不会在不安全的配置下意外地将其部署到公共互联网上。

您可以在 Datasette 手册中阅读关于Datasette 的身份验证方法

您可以安装 datasette-insert-unsafe 插件以在不安全模式下运行,该模式默认允许所有访问。

我建议将此插件与 datasette-auth-tokens 结合使用,后者提供了一种使用 API token 进行身份验证调用的机制。

然后,您可以在 datasette-insert 插件配置中使用“allow” 块来指定哪些已身份验证的 token 允许使用该 API。

以下是一个示例 metadata.json 文件,它将 /-/insert API 的访问权限限制为在 INSERT_TOKEN 环境变量中定义的 API token:

{
    "plugins": {
        "datasette-insert": {
            "allow": {
                "bot": "insert-bot"
            }
        },
        "datasette-auth-tokens": {
            "tokens": [
                {
                    "token": {
                        "$env": "INSERT_TOKEN"
                    },
                    "actor": {
                        "bot": "insert-bot"
                    }
                }
            ]
        }
    }
}

完成此配置后,您可以像这样启动 Datasette:

INSERT_TOKEN=abc123 datasette data.db -m metadata.json

现在,您可以使用 curl 向 API 发送数据,如下所示:

curl --request POST \
  -H "Authorization: Bearer abc123" \
  --data '[
      {
        "id": 3,
        "name": "Boris",
        "age": 1,
        "breed": "Husky"
      }
    ]' \
    'http://localhost:8001/-/insert/data/dogs'

或者使用 Python requests 库,如下所示:

requests.post(
    "http://localhost:8001/-/insert/data/dogs",
    json={"id": 1, "name": "Cleopaws", "age": 5},
    headers={"Authorization": "bearer abc123"},
)

细粒度权限

如上所述使用 "allow" 块会授予对 API 启用功能的完全权限。

该 API 实现了几个新的 Datasette 权限,其他插件可以使用这些权限来做出更细粒度的决策。

完整的权限集如下:

  • insert:all - 所有权限 - 这是上面描述的 "allow" 块使用的权限。参数:database_name
  • insert:insert-update - 将数据插入现有表或通过主键更新数据的能力。参数:(database_name, table_name)
  • insert:create-table - 创建新表的能力。参数:database_name
  • insert:alter-table - 向现有表添加列的能力(使用 ?alter=1)。参数:(database_name, table_name)

您可以使用像 datasette-permissions-sql 这样的插件来介入这些更详细的权限,以便对每个已身份验证的执行者可以采取的操作进行细粒度控制。

实现 permission_allowed() 插件钩子的插件可以完全控制这些权限决策。

跨域资源共享 (CORS)

如果您使用 datasette --cors 选项启动 Datasette,此插件提供的资源将添加以下 HTTP 头部:

Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: content-type,authorization
Access-Control-Allow-Methods: POST

开发

要在本地设置此插件,首先拷出代码。然后创建一个新的虚拟环境:

cd datasette-insert
python3 -m venv venv
source venv/bin/activate

现在安装依赖和测试:

pip install -e '.[test]'

运行测试:

pytest