跳转到主要内容

将附件存储在外部对象存储中

项目描述

Beta License: AGPL-3 OCA/storage Translate me on Weblate Try me on Runboat

在某些情况下,您需要将附件存储在Odoo文件存储以外的另一个系统中。例如,当您的部署基于多服务器架构以确保冗余和可扩展性时,您的附件必须以所有服务器都可以访问的方式存储。这样,您可以使用像NFS这样的共享存储系统或S3兼容的云存储,或...

此插件扩展了Odoo附件的存储机制,允许您使用Python库fsspec支持的任何存储文件系统,并通过fs_storage插件提供。

与Odoo不同,当文件存储在外部存储中时,此插件确保文件名保持其意义(在Odoo中,文件存储中的文件名是文件内容的校验和)。具体来说,文件名基于以下模式:'<name-without-extension>-<attachment-id>-<version>.<extension>'

此插件还向附件添加了两个新字段,用于从URL检索文件内容

  • 内部URL: 从Odoo文件存储检索文件内容。

  • 文件系统URL: 从外部存储检索文件内容。

注意

内部URL始终可用,但文件系统URL仅在附件存储在外部存储时才可用。特别关注尽可能减少通过Odoo提供存储在外部文件系统中的内容所需资源的消耗。默认情况下,实现基于外部文件系统和Odoo客户端应用程序之间内容的端到端流式传输。尽管如此,如果您的内容可通过外部文件系统上的URL访问,您可以通过配置存储以使用x-sendfile机制来提供服务,如果它在您的Odoo实例上已启用。在这种情况下,Odoo在内部URL提供的内容将通过nginx代理到文件系统URL。

最后但同样重要的是,插件在附件上添加了一个新的open方法。此方法允许您将附件作为文件打开。对于存储在文件存储或外部文件系统中的附件,它允许您直接从文件中读取和写入,因此可以最小化内存消耗,因为数据在写入数据库之前不会保留在内存中。

目录

用法

配置

配置通过在Odoo中创建文件系统存储记录来完成。要创建新的存储,请转到菜单设置 > 技术 > 文件存储并单击创建

除了可用于配置存储的常见字段外,在“附件”部分还提供了特定字段,用于配置附件在文件系统中存储的方式。

  • 优化目录路径:如果您需要防止单个目录中有太多文件,此选项很有用。它将根据附件的校验和(具有2级深度)创建目录结构。例如,如果校验和是123456789,则文件将存储在目录/path/to/storage/12/34/my_file-1-0.txt中。

  • 自动真空GC:当文件在Odoo中不再引用时,此选项用于自动从文件系统中删除文件。某些存储后端(如S3)可能对文件存储收费,因此删除不再需要的文件很重要。在某些情况下,此选项可能不受欢迎,例如,如果您正在使用存储后端存储与其他系统(如您的网站)共享的图像,并且您不希望在它们在其他系统中引用时从存储中删除文件。此机制基于用于收集要删除的文件的fs.file.gc模型。当从数据库中删除文件时,此模型会自动由ir.attachment模型填充。如果您禁用此选项,您将必须手动处理文件系统存储中的fs.file.gc记录。

  • 用作附件默认存储:此选项允许您声明存储为附件的默认存储。如果您已配置多个文件系统存储,您可以选择哪个将被用于附件的默认存储。一旦激活,未指定存储创建的附件将存储在此默认存储中。

  • 强制数据库默认附件规则:如果您想强制将一些附件存储在数据库中,即使已经配置了默认文件系统存储,此选项非常有用。这在您使用S3等存储后端时特别有用,因为网络延迟可能很高。此选项是一个JSON字段,允许您定义mimetypes和大小限制,低于此限制的附件将存储在数据库中。

    小图像(128、256)在Odoo的列表/看板视图中使用。我们希望它们读取速度快。它们通常小于50KB(默认配置),因此在数据库中占用的空间不大,但它们将从对象存储中读取得更快。

    无论大小如何,资源(application/javascript、text/css)都存储在数据库中

    • 数据库不会有成千上万个它们

    • 当然,性能更好

    • 数据库的可移植性更好:在复制生产实例进行开发时,包括资产

    默认配置是

    {“image/”:51200,“application/javascript”:0,“text/css”:0}

    其中,键是要配置的mimetypes的开始,值是附件保持在数据库中的大小限制以下。0表示没有限制。

    默认配置意味着

    • 图像mimetypes(image/png、image/jpeg等)大小小于50KB存储在数据库中

    • application/javascript无论大小都存储在数据库中

    • text/css无论大小都存储在数据库中

    此选项仅在用作附件默认文件系统存储的文件系统存储上可用。

还可以为链接到不同资源字段/模型的附件使用不同的FS存储。您可以直接在fs.storage上配置它,或在服务器环境文件中配置。

  • fs.storage:模型ids字段和字段ids字段将编码为哪些模型/字段使用此存储作为具有这些资源模型/字段的附件的默认存储。请注意,如果一个附件既有资源模型又有字段,它将首先使用字段明确链接的FS存储,如果找不到,则使用模型明确链接的存储。

  • 从服务器环境文件:在这种情况下,您只需提供以逗号分隔的模型列表(在model_xmlids键下)或字段列表(在field_xmlids键下)。为此,请使用Odoo提供的模型/字段XML ID。请参阅服务器环境部分以获取具体示例。

此模块的另一个关键功能是能够从URL访问附件。

  • 基本URL:这是用于从文件系统存储本身访问附件的基本URL。如果您的存储没有提供从URL访问文件的方法,则可以留空此字段。

  • 在URL中包含目录路径:通常配置在存储上的目录路径不会包含在URL中。如果想要包含它,可以激活此选项。

  • 使用X-Sendfile来服务内部URL:如果选中且Odoo位于支持x-sendfile的代理后面,则通过附件的内部URL提供的内容将由代理使用文件系统URL路径提供(如果已定义)。如果没有定义,则文件将由Odoo提供,将从文件系统存储读取内容进行流式传输。此选项有助于避免从Odoo提供文件,因此可以避免加载Odoo进程。

    要完全功能,此选项需要代理支持x-sendfile(Apache)或x-accel-redirect(Nginx)。您还必须通过为每个存储添加规则来配置代理,将根目录在“存储代码”的url重定向到服务文件的服务器。例如,如果您有一个代码为“my_storage”的存储,并在url“http://myserver.com”的服务器上提供文件服务,您必须在代理配置中添加以下规则:

    location /my_storage/ {
        internal;
        proxy_pass http://myserver.com;
    }

    使用此配置,对“/web/content/<att.id>/<att.name><att.extension>”的调用(存储在“my_storage”存储中)将生成由Odoo返回的响应,URI为/my_storage/<paht_in_storage>/<att.name>-<att.id>-<version><att.extension>,在头信息X-Accel-RedirectX-Sendfile中,并且代理将重定向到http://myserver.com/<paht_in_storage>/<att.name>-<att.id>-<version><att.extension>

    有关更多信息,请参阅https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/

  • 使用文件名混淆:如果选中,将使用内容的校验和混淆存储到文件系统存储中使用的文件名。这有助于避免在Odoo数据库外部暴露附件的真实文件名。文件名将通过使用内容的校验和来混淆。此选项用于在您的文件存储内容与其他系统(如您的网站)共享时,并希望保留有意义的文件名以确保SEO。此选项默认禁用。

服务器环境

通过使用服务器环境文件配置存储时,您可以提供以下键的值:

  • optimizes_directory_path

  • autovacuum_gc

  • base_url

  • is_directory_path_in_url

  • use_x_sendfile_to_serve_internal_url

  • use_as_default_for_attachments

  • force_db_for_default_attachment_rules

  • use_filename_obfuscation

  • model_xmlids

  • field_xmlids

例如,使用代码fsprod存储附件的默认存储配置可能如下所示:

[fs_storage.fsprod]
protocol=s3
options={"endpoint_url": "https://my_s3_server/", "key": "KEY", "secret": "SECRET"}
directory_path=my_bucket
use_as_default_for_attachments=True
use_filename_obfuscation=True
model_xmlids=base.model_res_lang,base.model_res_country
field_xmlids=base.field_res_partner__image_128

高级用法:将附件用作文件

附件上的open方法可以用来打开和将附件作为文件对象操作。该方法调用的返回对象实现了io.IOBase的方法。该方法可以像其他Python方法一样调用。在这种情况下,您需要在您的进程结束时关闭文件。

attachment = self.env.create({"name": "test.txt"})
the_file = attachment.open("wb")
try:
  the_file.write(b"content")
finally:
  the_file.close()

open调用的结果也可以在with块中使用。在这种情况下,当代码退出块时,文件会自动关闭。

attachment = self.env.create({"name": "test.txt"})
with attachment.open("wb") as the_file:
  the_file.write(b"content")

始终首选第二种方法。

当您的附件存储在Odoo文件存储或外部文件系统存储中时,每次您调用open方法时,都会创建一个新的文件。这种方式确保如果在事务回滚时原始内容被保留。尽管如此,您可能有使用情况,您可以直接写入现有文件。例如,您可以创建一个空的附件来存储csv报告,然后使用open方法直接将内容写入新文件。为了支持此类用例,可以传递参数new_version为False以避免创建新文件。

attachment = self.env.create({"name": "test.txt"})
with attachment.open("w", new_version=False) as f:
    writer = csv.writer(f, delimiter=";")
    ....

技巧与窍门

  • 在多阶段环境中工作时,附件的管理可能很棘手。例如,如果您有一个生产实例和一个基于生产环境备份的测试实例,您可能希望两个实例之间共享附件,但您不希望一个实例删除或修改另一个实例的附件。

    要这样做,您可以在预发布实例中添加一个新的存储,并将其声明为默认存储,用于附件。这样,所有新的附件都将存储在这个新的存储中,但生产实例上创建的附件仍然从生产存储中读取。请注意,将存储配置适应生产环境以使其只读。使用服务器环境文件是一种好方法。

变更日志

16.0.1.0.8 (2023-12-20)

错误修复

  • 修复了当存储设置为优化目录路径时检索附件文件的错误。(#312

16.0.1.0.6 (2023-12-02)

错误修复

  • 提高了创建附件或更新附件时的性能。

    在此更改之前,当计算fs_url时,即使值相同,计算出的值也会重新分配给fs_url属性。在许多情况下,值是相同的,重新分配是不必要的。遗憾的是,这种重新分配会产生副作用,将记录标记为脏,并在事务结束时生成SQL更新语句。(#307

16.0.1.0.5 (2023-11-29)

错误修复

  • 当通过名为fs的局部变量操作文件系统API时,我们观察到,当它在一个封闭作用域中错误地重新定义为以下示例时,会出现一些奇怪的行为:with fs.open(…) as fs。此提交通过重命名局部变量来修复此问题,从而避免了名称冲突。(#306

16.0.1.0.4 (2023-11-22)

错误修复

  • 修复了在没有目录路径的存储中计算附件url时的错误。(#302

16.0.1.0.3 (2023-10-17)

错误修复

  • 修复了技术模型访问错误,以便基本访问权限的用户能够上传附件。(#289

16.0.1.0.2 (2023-10-09)

错误修复

  • 确保与Python 3.9兼容。(#285

  • 如果存储不是默认存储所有附件,则调用get_force_db_for_default_attachment_rules方法必须返回一个空字典。(#286

错误跟踪器

错误在GitHub问题上追踪。如果遇到问题,请检查是否已报告您的问题。如果您是第一个发现它的,请帮助我们通过提供详细且受欢迎的反馈来解决这个问题。

不要直接联系贡献者关于支持或技术问题的帮助。

鸣谢

作者

  • Camptocamp

  • ACSONE SA/NV

贡献者

Thierry Ducrest <thierry.ducrest@camptocamp.com> Guewen Baconnier <guewen.baconnier@camptocamp.com> Julien Coux <julien.coux@camptocamp.com> Akim Juillerat <akim.juillerat@camptocamp.com> Thomas Nowicki <thomas.nowicki@camptocamp.com> Vincent Renaville <vincent.renaville@camptocamp.com> Denis Leemann <denis.leemann@camptocamp.com> Patrick Tombez <patrick.tombez@camptocamp.com> Don Kendall <kendall@donkendall.com> Stephane Mangin <stephane.mangin@camptocamp.com> Laurent Mignon <laurent.mignon@acsone.eu> Marie Lejeune <marie.lejeune@acsone.eu> Wolfgang Pichler <wpichler@callino.at> Nans Lefebvre <len@lambdao.dev>

维护者

此模块由OCA维护。

Odoo Community Association

ODoo社区协会(OCA)是一个非营利组织,其使命是支持Odoo功能的协作开发并推广其广泛应用。

当前维护者

lmignon

本模块是GitHub上的OCA/storage项目的组成部分。

欢迎您贡献力量。了解如何贡献,请访问https://odoo-community.org/page/Contribute

项目详情


下载文件

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

源代码分发

此版本没有提供源代码分发文件。请参阅有关生成分发归档的教程。

构建分发

odoo_addon_fs_attachment-17.0.1.0.2.2-py3-none-any.whl (102.8 kB 查看哈希值)

上传时间 Python 3

支持者