定义模块数据

重要

本教程是 服务器框架 101 教程的延伸。请确保您已完成该教程,并使用您之前构建的 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

小技巧

你的 IDE 可能有扩展程序,可以对 CSV 文件进行语法高亮显示。

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 模块创建一些示例数据。

字段

名称

大别墅

拖车房

状态

新建

已取消

描述

一个漂亮宽敞的别墅

拖车公园中的家

邮编

12345

54321

日期可用性

2020-02-02

1970-01-01

预期价格

1,600,000

100,000

销售价格

120,000

卧室

6

1

建筑面积

100

10

facades

4

4

车库

正确

False

花园

正确

花园面积

100000

花园朝向

南方

数据扩展

在基础培训中,我们在 Chapter 12: Inheritance 章节中了解到,我们可以继承(扩展)现有的视图。这是数据扩展的一个特殊案例:任何数据都可以在模块中进行扩展。

在您向新模块中的现有模型添加新字段时,可能希望为依赖模块中创建的记录填充这些字段。这是通过提供要扩展的记录的 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 键来设置关联字段。该键的值是您要链接的记录的 xml_id。请注意,xml_id 由首次声明数据的模块名称、一个点以及记录的 id 组成(如果您在声明该记录的模块中,仅使用 id 也可以)。

<odoo>
  <record id="id1" model="tutorial.example">
    <field name="related_id" ref="module.relatedid"/>
  </record>
</odoo>

Exercise

为您创建的房产创建一些示例数据报价。

使用 base 模块中定义的合作伙伴创建报价

业务伙伴

房产

价格

有效性

Azure Interior

大别墅

10000

14

Azure Interior

大别墅

1500000

14

装饰爱好者

大别墅

1500001

14

Exercise

确保您的两个演示房产都已创建,并且房产类型设置为住宅。

求值

字段的值并不总是简单的字符串,你可能需要对其进行计算。它也可以用于优化关联值的插入,或者因为某种约束要求你必须成批添加相关值。参见 :添加 X2many 字段

<odoo>
  <record id="id1" model="tutorial.example">
    <field name="year" eval="datetime.now().year+1"/>
  </record>
</odoo>

Exercise

您添加的报价始终应相对于模块的安装日期进行设置。

函数

你可能还需要在加载数据时执行 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、ID 为 id1 的记录的字段 related_id 中。

在 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 模块 会绕过此设置并始终加载数据。但通常情况下,不应该在生产数据库上执行此操作。

<odoo noupdate="1">
  <record id="id1" model="model">
    <field name="fieldA" eval="True"/>
  </record>
</odoo>

导入为 SQL

在某些情况下,直接通过 SQL 进行导入是有意义的。然而,这种做法不被推荐,因为它会绕过 ORM 的所有功能、计算字段(包括元数据)以及 Python 约束。

注解

通常使用原始 SQL 会绕过访问控制列表 (ACLs),并增加注入攻击的风险。

引用Odoo 中的安全性