跳转到主要内容

未提供项目描述

项目描述

Tests

ckanext-files

将文件作为CKAN的一等公民。直接上传、管理、删除文件并将它们附加到数据集、资源等。

需求

与核心CKAN版本的兼容性

CKAN版本 兼容?
2.8
2.9
2.10
master

ckanext-files v0.2支持CKAN v2.8和v2.9。从v1.0开始,此扩展切换到CKAN支持策略,即只支持两个最新的CKAN版本。例如,ckanext-files v1.0仅支持CKAN v2.10和v2.11。

v0.*将不会收到任何新功能,只有错误修复和小型改进。

建议通过pip安装扩展,因此您可能已经固定了所有需求。如果您使用此扩展的GitHub版本,请坚持使用vX.Y.Z标签以避免破坏性更改。在升级扩展之前,请检查变更日志。

安装

要安装ckanext-files

  1. 安装扩展

    # minimal installation
    pip install ckanext-files
    
    # Google Cloud Storage support
    pip install 'ckanext-files[gcs]'
    
  2. files添加到CKAN配置文件中的ckan.plugins设置中。

  3. 运行数据库迁移

    # CKAN >= v2.9
    ckan db upgrade -p files
    
    # CKAN == v2.8
    paster --plugin=ckanext-files files -c ckan.ini initdb
    

使用方法

配置存储

在上传任何文件之前,您必须配置一个命名的存储。告诉扩展程序使用哪个驱动程序(即数据存储的位置和方式),添加一些特定于存储的设置,然后您就可以开始了。让我们从Redis驱动程序开始,因为它在配置方面要求最少。

将以下行添加到CKAN配置文件中

ckanext.files.storage.my_storage.type = files:redis

看看这个选项。前缀ckanext.files.storage.将适用于每个与存储相关的配置选项。然后是my_storage。这是您的存储名称。它不会改变存储的行为,但确定如何组合选项,并帮助您同时使用多个存储。例如,以下配置添加了两个不同的存储:first_storage,其prefix设置为first:,以及second_storage,其前缀设置为second:

ckanext.files.storage.first_storage.type = files:redis
ckanext.files.storage.second_storage.type = files:redis

ckanext.files.storage.first_storage.prefix = first:
ckanext.files.storage.second_storage.prefix = second:

我们的存储称为my_storage,在存储的名称之后是选项名称type。它的值是files:redistype选项告诉我们将使用哪个驱动程序进行存储。files:redis是驱动程序的名称。

驱动程序名称的推荐格式是<EXTENSION_NAME>:<STORAGE_TYPE>。但这不是强制性的,所以您可以看到任何值。如果您不小心在驱动程序的名称中输入了错误,从v2.10开始,CKAN将在启动时显示错误消息,其中包含可用的驱动程序列表

Invalid configuration values provided:
ckanext.files.storage.my_storage.type: Value must be one of ['files:bq_google_cloud_storage', 'files:fs', 'files:public_fs', 'files:redis', 'files:google_cloud_storage']
Aborted!

存储已配置,因此我们可以实际上传文件。让我们使用ckanapi来完成这项任务。文件是通过files_file_create API操作创建的,这次我们必须向其中传递3个参数

  • name:上传文件的名称
  • upload:文件的内容
  • storage:存储文件的存储名称(我们刚刚配置了my_storage

最终的命令如下

ckanapi action files_file_create \
    name=hello.txt \
    upload='hello world' \
    storage=my_storage

这就是您看到的结果

{
  "atime": null,
  "completed": true,
  "ctime": "2024-03-12T22:08:05.185914",
  "id": "7f9a7676-5177-40f0-b610-0b47918fdccc",
  "mtime": null,
  "name": "hello.txt",
  "storage": "my_storage",
  "storage_data": {
    "content_type": "text/plain",
    "filename": "2f51aeff-96a5-4d79-8973-7867527d7f2e",
    "hash": "5eb63bbbe01eeed093cb22bb8f5acdc3",
    "size": 11
  }
}

现在前往Redis CLI并检查文件的内容。注意,您不能通过CKAN API获取内容,因为它是基于JSON的,并且下载文件不符合其原则。

默认情况下,Redis驱动程序将内容放在键<PREFIX><FILENAME>下。注意FILENAME。这是API响应中作为storage_data.filename可用的值(即,在我们的例子中为2f51aeff-96a5-4d79-8973-7867527d7f2e),而不是您刚刚上传的真正文件的名称。

PREFIX可以配置,但我们跳过了这一步,并得到了默认值:ckanext:files:default:file_content:。因此,我们文件的最终Redis键为ckanext:files:default:file_content:2f51aeff-96a5-4d79-8973-7867527d7f2e

redis-cli

127.0.0.1:6379> GET ckanext:files:default:file_content:2f51aeff-96a5-4d79-8973-7867527d7f2e
"hello world"

在我们继续之前,让我们使用创建时的ID删除文件

ckanapi action files_file_delete id=7f9a7676-5177-40f0-b610-0b47918fdccc

# ... response from api

redis-cli

127.0.0.1:6379> GET ckanext:files:default:file_content:2f51aeff-96a5-4d79-8973-7867527d7f2e
(nil)

代码中使用

如果您正在编写代码并想直接与存储交互,而无需通过API层,您可以通过扩展的许多公共函数来实现。

让我们首先配置文件系统存储。这次我们将使用存储名称default。这是“默认”存储名称——如果您在与它一起工作时没有明确指定存储的名称(例如,调用API操作),则使用default存储。因此,最好创建此存储而不是使用花哨的名称。

文件系统驱动程序有一个强制选项path,它控制文件存储的路径。如果路径不存在,则默认情况下存储将引发异常。但您也可以通过启用create_path选项来创建缺失的路径。这是我们的最终设置版本

ckanext.files.storage.default.type = files:fs
ckanext.files.storage.default.path = /tmp/example
ckanext.files.storage.default.create_path = true

现在我们将通过ckan shell CLI命令连接到CKAN shell并创建存储实例

from ckanext.files.shared import get_storage
storage = get_storage('default')

因为您已经全部配置完毕,所以剩下的工作相当直接。我们将上传文件,读取其内容,并在CKAN shell中删除它。

上传是最具挑战性的步骤。由于CKAN基于Flask,我们必须像Flask一样上传文件。为此,我们将创建一个werkzeug.datastructures.FileStorage实例,并将其构造函数传递字节数据流。之后,我们可以将对象传递给存储的upload方法,并指定上传的名称。

from werkzeug.datastructures import FileStorage
from io import BytesIO

upload = FileStorage(BytesIO(b'hello world'))
result = storage.upload('file.txt', upload, {})

print(result)

... {'filename': 'd65da0fd-299a-433c-850e-086fdc5ebb7e',
...  'content_type': None,
...  'size': 11,
...  'hash': '5eb63bbbe01eeed093cb22bb8f5acdc3'}

result包含存储管理文件所需的最小信息量。对于文件系统存储,它包括filename。如果您访问我们指定为存储path/tmp/example目录,您会看到一个与结果中的filename匹配的文件。并且其内容与我们的上传内容相匹配,这是一个相当预期的结果。

但是让我们回到shell中,尝试从Python代码中读取文件。我们将result传递给存储的stream方法,该方法根据我们的结果产生一个可读的缓冲区。此缓冲区具有read方法,因此我们可以像通常处理IO流一样处理该缓冲区。

buffer = storage.stream(result)
content = buffer.read()
print(content)

... b'hello world'

最后,我们需要删除该文件

storage.remove(result)

浏览器使用方法

您可以使用JavaScript CKAN模块上传文件。该扩展扩展了CKAN的Sandbox对象(在JS CKAN模块中作为this.sandbox可用),因此我们可以使用快捷方式直接从开发者工具上传文件。打开任何CKAN页面,切换到JS控制台,创建沙盒实例。在其内部,我们有files对象,该对象包含upload方法。此方法接受上传的File对象(与您可以从input[type=file]获取的对象相同)。

sandbox = ckan.sandbox()
await sandbox.files.upload(
  new File(["content"], "file.txt")
)

... {
...    "id": "d6fa3096-613a-4b16-a0eb-b7a6ec91d690",
...    "name": "file.txt",
...    "storage": "default",
...    "ctime": "2024-03-12T23:08:11.291971",
...    "mtime": null,
...    "atime": null,
...    "storage_data": {
...        "filename": "f484d116-cf6f-4238-80e5-905849873be0",
...        "content_type": "application/octet-stream",
...        "size": 7,
...        "hash": "9a0364b9e99bb480dd25e1f0284c8555"
...    },
...    "completed": true
... }

如果您仍然使用前一部分中配置的文件系统存储,切换到/tmp/example文件夹并检查其内容。

ls /tmp/example
... f484d116-cf6f-4238-80e5-905849873be0

cat f484d116-cf6f-4238-80e5-905849873be0
... content

通常,让我们使用upload承诺的ID删除文件

sandbox.client.call('POST', 'files_file_delete', {
  id: 'd6fa3096-613a-4b16-a0eb-b7a6ec91d690'
})

用户界面

此扩展提供基本的UI作为示例,建议您需要时构建自己的UI。但我们仍然可以使用默认功能进行测试。在浏览器中打开CKAN应用程序的/user/<YOUR USERNAME>/files页面。

Empty files page

选择文件

Selected file

单击播放按钮(具有三角形图标的按钮)并稍等片刻。如果没有变化,请检查JS控制台,它可以在存储配置不正确时显示一些错误。

Uploaded file

上传完成后,请重新加载页面以查看上传的文件。

Reloaded page with a single upload

配置

ckanext-files有两种类型的配置选项

  • 全局配置影响扩展的常见行为
  • 存储配置更改特定存储的行为,并且永远不会影响存储之外的内容

根据存储类型,存储的可用选项将改变。例如,files:fs存储类型需要控制上传存储的文件系统路径的path选项。files:redis存储类型接受定义Redis中存储的文件键前缀的prefix选项。所有特定存储选项始终具有形式ckanext.files.storage.<STORAGE>.<OPTION>

ckanext.files.storage.memory.prefix = xxx:
# or
ckanext.files.storage.my_drive.path = /tmp/hello

以下是存储非特定选项的列表。特定存储类型的详细信息可以在存储类型的专用部分中找到。

# Default storage used for upload when no explicit storage specified
# (optional, default: default)
ckanext.files.default_storage = default

# Configuration of the named storage.
# (optional, default: )
ckanext.files.storage.<NAME>.<OPTION> =

从CKAN v2.10开始,您可以通过配置声明CLI检查存储类型的所有可用选项。首先,将存储类型添加到配置文件

ckanext.files.storage.xxx.type = files:redis

现在运行显示插件所有可用配置选项的命令。

ckan config declaration files -d

由于已启用Redis存储适配器,您将看到与全局选项一起注册的所有Redis驱动程序选项

## ckanext-files ###############################################################
## ...
## Storage adapter used by the storage
ckanext.files.storage.xxx.type = files:redis
## The maximum size of a single upload.
## Supports size suffixes: 42B, 2M, 24KiB, 1GB. `0` means no restrictions.
ckanext.files.storage.xxx.max_size = 0
## Descriptive name of the storage used for debugging.
ckanext.files.storage.xxx.name = xxx
## Static prefix of the Redis key generated for every upload.
ckanext.files.storage.xxx.prefix = ckanext:files:default:file_content:

有时,如果存储有必需的配置选项,您会看到验证错误。让我们尝试使用files:fs存储而不是Redis

ckanext.files.storage.xxx.type = files:fs

现在尝试运行ckan config declaration files -d将显示一个错误,因为缺少必需的path选项

Invalid configuration values provided:
ckanext.files.storage.xxx.path: Missing value
Aborted!

添加所需选项以满足应用程序要求

ckanext.files.storage.xxx.type = files:fs
ckanext.files.storage.xxx.path = /tmp

再次运行CLI命令。这次您将看到允许的选项列表

## ckanext-files ###############################################################
## ...
## Storage adapter used by the storage
ckanext.files.storage.xxx.type = files:fs
## The maximum size of a single upload.
## Supports size suffixes: 42B, 2M, 24KiB, 1GB. `0` means no restrictions.
ckanext.files.storage.xxx.max_size = 0
## Descriptive name of the storage used for debugging.
ckanext.files.storage.xxx.name = xxx
## Path to the folder where uploaded data will be stored.
ckanext.files.storage.xxx.path =
## Create storage folder if it does not exist.
ckanext.files.storage.xxx.create_path = false

项目详细信息


下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。

源代码发行版

ckanext_files-0.3.0.tar.gz (94.2 kB 查看哈希值)

上传时间 源代码

构建发行版

ckanext_files-0.3.0-py3-none-any.whl (110.2 kB 查看哈希值)

上传时间 Python 3

支持者