资产¶
在 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 中资源的处理流程如下:
调用某个资源包时(例如
t-call-assets="web.assets_common"),会生成一个空的资源列表获取与该资源包匹配的所有
ir.asset类型记录,并按序号排序。然后处理序号严格小于 16 的所有记录,并将其应用到当前的资源列表。所有在清单文件中为该资源包声明了资源的模块,都会将其资源操作应用到该列表。这一过程遵循模块依赖顺序(例如
web的资源会先于website处理)。如果某个指令试图添加列表中已存在的文件,则不会对该文件做任何处理。换言之,列表中只保留文件的第一次出现。其余的
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参数描述的资源。该参数是一个对象,可包含以下键:键
类型
说明
jsLibsstring[]JavaScript 文件的 url 列表
cssLibsstring[]css 文件的 url 列表
- useAssets(assets)¶
- 参数
assets (
Object()) – 应加载的各种资源的描述
当组件需要在其
onWillStart方法中加载一些资源时,此 hook 很有用。它在内部调用loadAssets。
资源模型(ir.asset)¶
大多数情况下,清单文件中声明的资源已基本够用。但为了更灵活,框架还支持在数据库中声明的动态资源。
这是通过创建 ir.asset 记录实现的。这些记录的处理方式与在模块清单文件中发现的一样,并且提供与清单文件中等价物相同的表达能力。
name资源记录的名称(用于识别)。
bundle将应用该资源的资源包。
directive(默认值=append)此字段决定如何解释
path以及(在需要时)target。以下是可用指令及其必需参数的列表:append:
pathprepend:
pathbefore:
target、pathafter:
target、pathinclude:
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 值的内容。