资产

在 Odoo 中管理资源并不像在其他一些应用中那样简单。原因之一是,我们有各种不同的场景,其中只需要部分资源,而不是全部资源。例如,Web 客户端、销售点应用、网站甚至移动应用的需求各不相同。此外,有些资源可能很大,但很少需要:在这种情况下,我们可能希望它们被 延迟加载(按需)。

资源类型

有三种不同的资源类型:代码(js 文件)、样式(css 或 scss 文件)和模板(xml 文件)。

代号

Odoo 支持 三种不同的 javascript 文件。所有这些文件随后都会被处理(原生 JS 模块会被转换为 odoo 模块),然后被压缩(如果不在 debug=assets 模式 下)并拼接。结果随后会保存为一个文件附件。这些文件附件通常通过页面 <head> 部分的 <script> 标签加载(作为静态文件)。

样式

样式可以使用 css 或 scss 完成。与 javascript 文件一样,这些文件会被处理(scss 文件会转换为 css),然后被压缩(同样,如果不在 debug=assets 模式 下)并拼接。结果随后会保存为一个文件附件。它们通常通过页面 <head> 部分的 <link> 标签加载(作为静态文件)。

模板

模板(静态 xml 文件)的处理方式不同:它们只是在需要时才从文件系统读取,然后拼接。

每当浏览器加载 odoo 时,都会调用 /web/webclient/qweb/ 控制器来获取 模板。

值得注意的是,在大多数情况下,浏览器只在第一次加载页面时执行一次请求。这是因为每个资源都关联了一个校验和,该校验和会被注入到页面源码中。随后校验和会被添加到 URL 中,这意味着可以安全地将缓存头设置为较长的时间。

资源包

Odoo 资源按 包 分组。每个包(即特定类型(xml、js、css 或 scss)的 文件路径列表)都列在 模块清单文件 中。可以使用 glob 语法声明文件,这意味着你可以用一行声明多个资源文件。

包在每个模块的 __manifest__.py 中定义,使用专门的 assets 键,该键包含一个字典。字典将包名称(键)映射到它们所包含的文件列表(值)。它看起来像这样:

'assets': {
    'web.assets_backend': [
        'web/static/src/xml/**/*',
    ],
    'web.assets_common': [
        'web/static/lib/bootstrap/**/*',
        'web/static/src/js/boot.js',
        'web/static/src/js/webclient.js',
        'web/static/src/xml/webclient.xml',
    ],
    'web.assets_unit_tests': [
        'web/static/src/js/webclient.test.js',
    ],
},

以下列出大多数 Odoo 开发者都需要了解的一些重要资源包:

  • web.assets_common:此资源包包含 Web 客户端、网站以及销售点共用的多数资源。它应当包含 Odoo 框架较低层次的构建块。请注意,它包含 boot.js 文件,该文件定义了 Odoo 模块系统。

  • web.assets_backend:此资源包包含 Web 客户端专用的代码(特别是 Web 客户端、动作管理器、视图和静态 XML 模板)

  • web.assets_frontend:此资源包涵盖公共网站专用的全部内容:电子商务、门户、论坛、博客……

  • web.assets_unit_tests:所有 JavaScript 单元测试代码(测试、辅助函数、模拟对象)

作业

通常,处理资源很简单:只需向 assets_common 或 assets_backend 等常用资源包添加一些新文件。不过还有其他操作可用于处理一些更为特定的场景。

请注意,所有以某个资源文件为目标的指令(即 before、after、replace 和 remove)都要求该文件事先已声明,无论是在层级更高的清单文件中,还是在序号更小的 ir.asset 记录中。

append

此操作添加一个或多个文件。由于它是最常见的操作,只需使用文件名即可完成:

'web.assets_common': [
    'my_addon/static/src/js/**/*',
],

默认情况下,向资源包添加一个普通字符串,会将匹配该 glob 模式的文件追加到资源包末尾。显然,该模式也可以直接是单个文件路径。

prepend

将一个或多个文件添加到资源包开头。

当你需要在资源包中将某个文件放在其他文件之前(例如 css 文件)时,这很有用。prepend 操作使用以下语法调用:('prepend', <path>)。

'web.assets_common': [
    ('prepend', 'my_addon/static/src/css/bootstrap_overridden.scss'),
],

before

将一个或多个文件添加到指定文件之前。

仅将文件前置到资源包开头可能不够精确。before 指令可用于将给定文件紧接在目标文件 之前 添加。它通过将普通路径替换为三元组 ('before', <target>, <path>) 来声明。

'web.assets_common': [
    ('before', 'web/static/src/css/bootstrap_overridden.scss', 'my_addon/static/src/css/bootstrap_overridden.scss'),
],

after

将一个或多个文件添加到指定文件之后。

与 before 相同,只是将匹配的文件紧接在目标文件 之后 追加。它通过将普通路径替换为三元组 ('after', <target>, <path>) 来声明。

'web.assets_common': [
    ('after', 'web/static/src/css/list_view.scss', 'my_addon/static/src/css/list_view.scss'),
],

include

使用嵌套的资源包。

include 指令是一种在其他资源包中使用某个资源包的方式,可尽量减小清单文件的体积。在 Odoo 中,我们使用子资源包(按约定以下划线为前缀)来集中存放多个其他资源包共用的文件。然后你可以像这样以键值对 ('include', <bundle>) 的形式指定子资源包:

'web.assets_common': [
    ('include', 'web._primary_variables'),
],

remove

移除一个或多个文件。

在某些情况下,你可能希望从资源包中移除一个或多个文件。这可以通过 remove 指令并指定键值对 ('remove', <target>) 来实现:

'web.assets_common': [
    ('remove', 'web/static/src/js/boot.js'),
],

replace

用一个或多个文件替换某个资源文件。

假设某个资源不仅需要移除,而且你还想在完全相同的位置插入该资源的新版本。这可以用 replace 指令通过三元组 ('replace', <target>, <path>) 来实现:

'web.assets_common': [
    ('replace', 'web/static/src/js/boot.js', 'my_addon/static/src/js/boot.js'),
],

加载顺序

资源的加载顺序有时非常关键,且必须是确定的,这主要涉及样式表的优先级和设置脚本。Odoo 中资源的处理流程如下:

  1. 调用某个资源包时(例如 t-call-assets="web.assets_common"),会生成一个空的资源列表

  2. 获取与该资源包匹配的所有 ir.asset 类型记录,并按序号排序。然后处理序号严格小于 16 的所有记录,并将其应用到当前的资源列表。

  3. 所有在清单文件中为该资源包声明了资源的模块,都会将其资源操作应用到该列表。这一过程遵循模块依赖顺序(例如 web 的资源会先于 website 处理)。如果某个指令试图添加列表中已存在的文件,则不会对该文件做任何处理。换言之,列表中只保留文件的第一次出现。

  4. 其余的 ir.asset 记录(序号大于或等于 16 的记录)随后也会被处理并应用。

在清单文件中声明的资源可能需要按特定顺序加载,例如加载 lib 文件夹时,jquery.js 必须在所有其他 jquery 脚本之前加载。一种解决方案是创建一条序号更小或使用 ‘prepend’ 指令的 ir.asset 记录,但还有一种更简单的方法。

由于资源列表中每个文件路径的唯一性是有保证的,你可以在包含某个文件的 glob 之前单独提及该文件。这样该文件就会出现在列表中 glob 所含其他文件之前。

'web.assets_common': [
    'my_addon/static/lib/jquery/jquery.js',
    'my_addon/static/lib/jquery/**/*',
],

注解

模块 b 若要移除或替换模块 a 中声明的资源,就必须依赖模块 a。尝试对尚未声明的资源进行操作会导致错误。

延迟加载

有时动态加载文件和/或资源包很有用,例如只在需要时才加载某个库。为此,Odoo 框架提供了一些辅助函数,位于 @web/core/assets 中。

await loadAssets({
    jsLibs: ["/web/static/lib/stacktracejs/stacktrace.js"],
});
loadAssets(assets)
参数
  • assets (Object()) – 应加载的各种资源的描述

退货

Promise<void>

加载由 assets 参数描述的资源。该参数是一个对象,可包含以下键:

键

类型

说明

jsLibs

string[]

JavaScript 文件的 url 列表

cssLibs

string[]

css 文件的 url 列表

useAssets(assets)
参数
  • assets (Object()) – 应加载的各种资源的描述

当组件需要在其 onWillStart 方法中加载一些资源时,此 hook 很有用。它在内部调用 loadAssets。

资源模型(ir.asset)

大多数情况下,清单文件中声明的资源已基本够用。但为了更灵活,框架还支持在数据库中声明的动态资源。

这是通过创建 ir.asset 记录实现的。这些记录的处理方式与在模块清单文件中发现的一样,并且提供与清单文件中等价物相同的表达能力。

name

资源记录的名称(用于识别)。

bundle

将应用该资源的资源包。

directive (默认值= append)

此字段决定如何解释 path 以及(在需要时) target。以下是可用指令及其必需参数的列表:

  • append:path

  • prepend:path

  • before:target、path

  • after:target、path

  • include:path (解释为 资源包名称)

  • remove:path (解释为要移除的 目标资源)

  • replace:target、path

path

一个定义以下内容之一的字符串:

  • addons 文件系统中某个资源文件的 相对路径;

  • addons 文件系统中一组资源文件的 glob 模式;

  • 指向附件或外部资源文件的 URL;

  • 使用 include 指令时的 资源包名称。

target

用于指定资源包中位置的目标文件。只能与 replace、before 和 after 指令一起使用。

active (默认值= True)

记录是否处于启用状态

sequence (默认值= 16)

资源记录的加载顺序(升序)。序号小于 16 表示该资源会在清单文件中声明的资源 之前 处理。

更多内容

请注意,ir.asset 的主要用例是网站相关的应用,因为它允许有条件的资源(例如启用某个样式选项时)。

在这种情况下,在 XML 中定义记录时,应优先使用 <asset id="..."> 语法,而不是 <record id="..." model="ir.asset"> 语法。

请参阅 asset,尤其是关于 active 值的内容。