第四章:模型和基本字段

上一章节 的最后,我们能够创建一个Odoo模块。然而,此时它仍然是一个空壳,无法存储任何数据。在我们的房地产模块中,我们希望将与属性(名称、描述、价格、居住面积等)相关的信息存储在数据库中。Odoo框架提供了工具来简化数据库交互。

在继续练习之前,请确保已安装 estate 模块,即在应用程序列表中必须显示为“已安装”。

警告

不要使用可变的全局变量。

一个Odoo实例可以在同一个python进程中并行运行多个数据库。每个数据库上可能安装了不同的模块,因此我们不能依赖于会根据安装的模块而更新的全局变量。

对象关系映射

参考: 有关此主题的文档可以在 模型 API 中找到。

注解

目标:在本节结束时,应该创建表格 estate_property

$ psql -d rd-demo
rd-demo=# SELECT COUNT(*) FROM estate_property;
count
-------
    0
(1 row)

Odoo 的一个关键组件是 ORM 层。这一层避免了手动编写大部分 SQL 语句,并提供了可扩展性和安全性服务2.

业务对象被声明为扩展了Python类的类,它们继承了 Model ,将它们整合到自动化的持久化系统中。

模型可以通过在其定义中设置属性来进行配置。最重要的属性是: _name ,它是必需的,并定义了模型在Odoo系统中的名称。下面是一个模型的最小定义:

from odoo import models

class TestModel(models.Model):
    _name = "test_model"

这个定义足以让ORM生成一个名为 test_model 的数据库表。按照惯例,所有的模型都位于 models 目录中,每个模型在自己的Python文件中定义。

看一下如何定义 crm_recurring_plan 表以及如何导入相应的Python文件:

  1. 模型定义在文件 crm/models/crm_recurring_plan.py (参见 这里)

  2. 文件 crm_recurring_plan.py 被导入到 crm/models/__init__.py 中(参见 here

  3. 文件夹 modelscrm/__init__.py 中被导入(参见 here

Exercise

定义房地产属性模型。

根据CRM模块中给出的示例,为 estate_property 表创建适当的文件和文件夹。

创建文件后,为 estate.property 模型添加最小定义。

修改Python文件后需要重新启动Odoo服务器。当我们重新启动服务器时,我们将添加参数 -d-u

$ ./odoo-bin --addons-path=addons,../enterprise/,../tutorials/ -d rd-demo -u estate

-u estate 意味着我们要升级 estate 模块,即 ORM 将应用数据库模式更改。 在这种情况下,它会创建一个新表。 -d rd-demo 意味着升级应该在 rd-demo 数据库上执行。 -u 应该始终与 -d 结合使用。

在启动过程中,您应该会看到以下警告:

...
WARNING rd-demo odoo.models: The model estate.property has no _description
...
WARNING rd-demo odoo.modules.loading: The model estate.property has no access rules, consider adding one...
...

如果是这种情况,那么你应该没问题!为了确保,可以使用 psql 进行双重检查,就像 Goal 中演示的那样。

Exercise

添加描述。

在你的模型中添加一个 _description 来消除其中一个警告。

模型字段

参考: 有关此主题的文档可以在 字段 API 中找到。

字段用于定义模型可以存储什么以及它们存储在哪里。字段在模型类中定义为属性:

from odoo import fields, models

class TestModel(models.Model):
    _name = "test_model"
    _description = "Test Model"

    name = fields.Char()

The name field is a Char which will be represented as a Python unicode str and a SQL VARCHAR.

类型

注解

Goal: at the end of this section, several basic fields should have been added to the table estate_property:

$ psql -d rd-demo

rd-demo=# \d estate_property;
                                            Table "public.estate_property"
    Column       |            Type             | Collation | Nullable |                   Default
--------------------+-----------------------------+-----------+----------+---------------------------------------------
id                 | integer                     |           | not null | nextval('estate_property_id_seq'::regclass)
create_uid         | integer                     |           |          |
create_date        | timestamp without time zone |           |          |
write_uid          | integer                     |           |          |
write_date         | timestamp without time zone |           |          |
name               | character varying           |           |          |
description        | text                        |           |          |
postcode           | character varying           |           |          |
date_availability  | date                        |           |          |
expected_price     | double precision            |           |          |
selling_price      | double precision            |           |          |
bedrooms           | integer                     |           |          |
living_area        | integer                     |           |          |
facades            | integer                     |           |          |
garage             | boolean                     |           |          |
garden             | boolean                     |           |          |
garden_area        | integer                     |           |          |
garden_orientation | character varying           |           |          |
Indexes:
    "estate_property_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "estate_property_create_uid_fkey" FOREIGN KEY (create_uid) REFERENCES res_users(id) ON DELETE SET NULL
    "estate_property_write_uid_fkey" FOREIGN KEY (write_uid) REFERENCES res_users(id) ON DELETE SET NULL

字段可以分为两大类:’简单字段’,即直接存储在模型表中的原子值,和’关系字段’,它们链接同一模型或不同模型的记录。

简单字段示例为 BooleanFloatCharTextDateSelection

Exercise

向房地产物业表添加基本字段。

将以下基本字段添加到表中:

字段

类型

名称

字符

描述

文本

邮政编码

字符

可用日期

日期

期望价格

浮点数

销售价格

浮点数

卧室数

整数

生活区域

整数

门面

整数

车库

布尔值

花园

布尔值

花园面积

整数

花园方向

选择

The garden_orientation field must have 4 possible values: ‘North’, ‘South’, ‘East’ and ‘West’. The selection list is defined as a list of tuples, see here for an example.

当字段添加到模型中时,请使用 -u estate 重新启动服务器

$ ./odoo-bin --addons-path=addons,../enterprise/,../tutorials/ -d rd-demo -u estate

连接到 psql 并检查表格 estate_property 的结构。你会注意到表格中还添加了一些额外的字段。我们稍后会重新讨论它们。

常用属性

注解

Goal: at the end of this section, the columns name and expected_price should be not nullable in the table estate_property:

rd-demo=# \d estate_property;
                                            Table "public.estate_property"
    Column       |            Type             | Collation | Nullable |                   Default
--------------------+-----------------------------+-----------+----------+---------------------------------------------
...
name               | character varying           |           | not null |
...
expected_price     | double precision            |           | not null |
...

与模型本身类似,字段可以通过传递配置属性作为参数进行配置:

name = fields.Char(required=True)

所有字段都有一些可用的属性,以下是最常见的属性:

string (str, default: field’s name)

用户界面中字段的标签(用户可见)。

required (bool, default: False)

如果 True,字段不能为空。它必须要么有一个默认值,要么在创建记录时始终给定一个值。

help (str, default: '')

为用户提供UI中的长形帮助工具提示。

index`(``bool`,默认值:False

请求Odoo在该列上创建一个 数据库索引 _。

Exercise

为现有字段设置属性。

添加以下属性:

字段

属性

名称

必填

期望价格

必填

重启服务器后,两个字段都应该是非空的。

自动字段

参考: 有关此主题的文档可以在 自动字段 中找到。

你可能已经注意到你的模型有一些你没有定义的字段。Odoo 在所有模型中创建了一些字段1。这些字段由系统管理,不能被写入,但如果有用或必要,它们可以被读取:

id (Id)

模型记录的唯一标识符。

create_date (Datetime)

记录创建日期。

create_uid (Many2one)

创建记录的用户。

write_date (Datetime)

记录的最后修改日期。

write_uid (Many2one)

最后修改记录的用户。

现在我们已经创建了我们的第一个模型,让我们 添加一些安全性!

1

可以 禁用某些字段的自动创建

2

编写原始的 SQL 查询是可能的,但需要谨慎,因为这将绕过所有 Odoo 的身份验证和安全机制。