定义模块数据

重要

本教程是 服务器框架入门 教程的扩展。确保您已完成该教程,并使用您构建的 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 模块创建一些演示数据。

字段

值(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

您添加的报价应始终与模块安装日期相关联。

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 约束。

注解

通常,使用原生 SQL 还会绕过 ACL,并增加注入攻击的风险。

参考Odoo 中的安全性