定义模块数据¶
重要
本教程是 服务器框架入门 教程的扩展。确保您已完成该教程,并使用您构建的 estate
模块作为本教程练习的基础。
数据类型¶
主数据¶
主数据通常是模块的技术或业务需求的一部分。换句话说,这类数据对于模块正常运行通常是必需的。安装模块时,这些数据将始终被安装。
我们之前已经接触过技术数据,因为我们已经定义了 视图 和 操作 。这些是一种主数据。
除了技术数据外,还可以定义业务数据,例如国家、货币、计量单位,以及完整的国家本地化(法律报告、税务定义、会计科目表)等更多内容……
演示数据¶
除了主数据(它们是模块正常运行的必要条件),我们还喜欢为演示目的准备一些数据:
帮助销售代表快速进行演示。
为开发人员提供一组可用的数据,用于测试新功能,并查看这些新功能在他们可能未添加的数据上的表现。
测试数据是否正确加载且不会引发错误。
在创建新数据库时快速设置大部分功能以供使用。
如果您不明确表示不需要演示数据,则在启动服务器时会自动加载它。这可以通过数据库管理器或命令行完成。
$ ./odoo-bin -h
Usage: odoo-bin [options]
Options:
--version show program's version number and exit
-h, --help show this help message and exit
Common options:
[...]
--without-demo=WITHOUT_DEMO
disable loading demo data for modules to be installed
(comma-separated, use "all" for all modules). Requires
-d and -i. Default is none
[...]
$ ./odoo-bin --addons-path=... -d db -i account --without-demo=all
数据声明¶
清单¶
参考:与此主题相关的文档可以在 模块清单文件 中找到。
数据可以使用 CSV 或 XML 声明。包含数据的每个文件都必须添加到清单文件中才能被加载。
在清单文件中用于添加新数据的键是 data
(用于主数据)和 demo
(用于演示数据)。两个值都应该是字符串列表,表示声明数据的文件的相对路径。
通常,演示数据位于 demo
文件夹中,视图和操作位于 views
文件夹中,与安全相关的数据位于 security
文件夹中,其他数据则位于 data
文件夹中。
如果您的工作目录结构如下:
estate
├── data
│ └── master_data.xml
├── demo
│ └── demo_data.xml
├── models
│ ├── *.py
│ └── __init__.py
├── security
│ └── ir.model.access.csv
├── views
│ └── estate_property_offer_views.xml
├── __init__.py
└── __manifest__.py
您的清单文件应如下所示:
# -*- coding: utf-8 -*-
{
"name": "Real Estate",
"depends": [
...
],
"data": [
"security/ir.model.access.csv", # CSV and XML files are loaded at the same place
"views/estate_property_offer_views.xml", # Views are data too
"data/master_data.xml", # Split the data in multiple files depending on the model
],
"demo": [
"demo/demo_data.xml",
]
"application": True,
}
CSV¶
参考:与此主题相关的文档可以在 CSV 数据文件 中找到。
声明简单数据的最简单方法是使用 CSV 格式。然而,其功能有限:适用于简单的长列表模型,但其他情况下建议使用 XML。
id,field_a,field_b,related_id:id
id1,valueA1,valueB1,module.relatedid
id2,valueA2,valueB2,module.relatedid
Exercise
为 estate
模块添加一些标准的房地产物业类型:住宅、商业、工业和土地。这些数据应始终安装。
XML¶
参考:与此主题相关的文档可以在 数据文件 中找到。
当需要创建的数据更复杂时,使用 XML 可能会很有用,甚至是必要的。
<odoo>
<record id="id1" model="tutorial.example">
<field name="field_a">valueA1</field>
<field name="field_b">valueB1</field>
</record>
<record id="id2" model="tutorial.example">
<field name="field_a">valueA2</field>
<field name="field_b">valueB2</field>
</record>
</odoo>
Exercise
为 estate
模块创建一些演示数据。
字段 |
值(Values) |
值(Values) |
---|---|---|
名称 |
大别墅(Big Villa) |
拖车房屋(Trailer home) |
状态(state) |
新建(New) |
已取消 |
描述 |
一座漂亮且宽敞的别墅 |
拖车公园中的房屋 |
邮政编码(postcode) |
12345 |
54321 |
可用日期(date_availability) |
2020-02-02 |
1970-01-01 |
预期价格(expected_price) |
1,600,000 |
100,000 |
销售价格(selling_price) |
120,000 |
|
卧室数量(bedrooms) |
6 |
1 |
生活区域面积(living_area) |
100 |
10 |
立面数量(facades) |
4 |
4 |
车库(garage) |
True |
否 |
花园(garden) |
True |
|
花园面积(garden_area) |
100000 |
|
花园朝向(garden_orientation) |
南(South) |
数据扩展¶
在核心培训期间,我们在 第 12 章:继承 章节中看到可以继承(扩展)现有的视图。这是一个特殊的数据扩展案例:任何数据都可以在模块中扩展。
当您在新模块中为现有模型添加新字段时,可能希望在依赖模块中创建的记录上填充这些字段。这是通过提供要扩展记录的 xml_id
实现的。它不会替换记录,而是将 field_c
设置为给定值以用于两条记录。
<odoo>
<record id="id1" model="tutorial.example">
<field name="field_c">valueC1</field>
</record>
<record id="id2" model="tutorial.example">
<field name="field_c">valueC2</field>
</record>
</odoo>
ref
¶
可以通过 ref
键设置相关字段。该键的值是要链接记录的 xml_id
。请记住,xml_id
由首次声明数据的模块名称、一个点和记录的 id
组成(如果您在声明它的模块中,仅使用 id
也可以)。
<odoo>
<record id="id1" model="tutorial.example">
<field name="related_id" ref="module.relatedid"/>
</record>
</odoo>
Exercise
为您创建的属性创建一些演示数据报价。
使用在 base
中定义的合作伙伴创建报价
合作伙伴(Partner) |
房地产(Estate) |
价格(Price) |
有效期(Validity) |
---|---|---|---|
Azure Interior |
大别墅(Big Villa) |
10000 |
14 |
Azure Interior |
大别墅(Big Villa) |
1500000 |
14 |
Deco Addict |
大别墅(Big Villa) |
1500001 |
14 |
Exercise
确保您的两个演示属性在创建时将其物业类型设置为住宅。
eval
¶
分配给字段的值并不总是简单的字符串,有时需要计算它。它还可以用于优化相关值的插入,或者因为约束条件要求您批量添加相关值。参见 : 添加 X2many 字段 。
<odoo>
<record id="id1" model="tutorial.example">
<field name="year" eval="datetime.now().year+1"/>
</record>
</odoo>
Exercise
您添加的报价应始终与模块安装日期相关联。
search
¶
有时,您需要调用 ORM 执行 search
操作。这无法通过 CSV 格式实现。
<odoo>
<record id="id1" model="account.move.line">
<field name="account_id" search="[
('user_type_id', '=', ref('account.data_account_type_direct_costs')),
('company_id', '=', obj().env.company.id)]
"/>
</record>
</odoo>
在此代码片段中,它之所以必要是因为主数据依赖于已安装的本地化设置。
function
¶
加载数据时,您可能还需要执行 Python 代码。
<function model="tutorial.example" name="action_validate">
<value eval="[ref('demo_invoice_1')]"/>
</function>
Exercise
通过点击“接受报价”按钮验证其中一个演示数据报价。拒绝其他报价。
添加 X2many 字段¶
参考:与此主题相关的文档可以在 Command
中找到。
如果需要在 One2many 或 Many2many 字段中添加相关数据,可以通过使用 Command
方法来实现。
<odoo>
<record id="id1" model="tutorial.example">
<field name="related_ids" eval="[
Command.create({
'name': 'My name',
}),
Command.create({
'name': 'Your name',
}),
Command.link(ref('model.xml_id')),
]"/>
</record>
</odoo>
Exercise
创建一个新的属性,但这次直接在与报价相关的 One2many 字段中创建一些报价。
访问数据¶
警告
您绝不应在演示数据声明之外访问演示数据,甚至在测试中也不行。
有多种方式可以访问主数据/演示数据。
在 Python 代码中,您可以使用 env.ref(self, xml_id, raise_if_not_found=True)
方法。它返回与指定的 xml_id
关联的记录集。
在 XML 中,您可以像这样使用 ref
键:
<odoo>
<record id="id1" model="tutorial.example">
<field name="related_id" ref="module.relatedid"/>
</record>
</odoo>
它将调用 ref 方法,并将返回记录的 ID 存储在类型为 tutorial.example
的记录的字段 related_id
中,其 ID 为 id1
。
在 CSV 中,列标题必须带有 :id
或 /id
后缀。
id,parent_id:id,name
"child1","module.parent","Name1"
"child2","module.parent","Name2"
"child3","module.parent","Name3"
在 SQL 中,情况更为复杂,请参阅 高级部分 。
警告
用户始终可以删除数据。编写代码时务必考虑这一点并采取防御性编程。
高级¶
什么是 XML ID?¶
由于我们不希望在数据库的每个 SQL 表中都添加一个 xml_id
列,因此需要一种机制来存储它。这是通过 ir.model.data
模型实现的。
它包含记录的名称(即 xml_id
)、定义它的模块、定义它的模型以及其 ID。
不更新¶
使用 noupdate
标志创建的记录在升级创建它们的模块时不会被更新,但如果它们尚不存在,则会被创建。
注解
odoo-bin -i module
将绕过此设置并始终加载数据。但通常不应在生产数据库上执行此操作。
<odoo noupdate="1">
<record id="id1" model="model">
<field name="fieldA" eval="True"/>
</record>
</odoo>
作为 SQL 导入¶
在某些情况下,直接以 SQL 方式导入是有意义的。然而,这并不推荐,因为它绕过了 ORM 的所有功能、计算字段(包括元数据)和 Python 约束。