第 3 章:模型与基本字段¶
在 上一章 末尾,我们成功创建了一个 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。
业务对象被声明为继承 Model 的 Python 类,从而被集成到自动持久化系统中。
模型可以通过在其定义中设置属性来进行配置。最重要的属性是 _name,它是必需的,用于定义模型在 Odoo 系统中的名称。以下是一个模型的最小定义:
from odoo import models
class TestModel(models.Model):
_name = "test_model"
这个定义足以让 ORM 生成一个名为 test_model 的数据库表。按照约定,所有模型都位于 models 目录中,且每个模型都定义在各自的 Python 文件里。
请看看 crm_recurring_plan 表是如何定义的,以及对应的 Python 文件是如何被导入的:
该模型定义在文件
crm/models/crm_recurring_plan.py中(参见 此处)文件
crm_recurring_plan.py在crm/models/__init__.py中被导入(参见 此处)文件夹
models在crm/__init__.py中被导入(参见 此处)
练习
定义房地产的房产模型。
参照 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 再核对一次。
练习
添加描述。
为你的模型添加 _description,以消除其中一条警告。
模型字段¶
参考:本主题相关的文档可在 字段 API 中找到。
字段用于定义模型能存储什么数据以及这些数据存放在何处。字段在模型类中以属性的形式定义:
from odoo import fields, models
class TestModel(models.Model):
_name = "test_model"
_description = "Test Model"
name = fields.Char()
name 字段是一个 Char,它会表示为 Python 的 unicode str 和 SQL 的 VARCHAR。
类型¶
注解
目标:本节结束时,应已向表 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
字段大体分为两类:“简单”字段,即直接存储在模型表中的原子值;以及“关联”字段,用于链接记录(同一模型或不同模型的记录)。
简单字段的例子包括 Boolean、Float、Char、Text、Date 和 Selection。
练习
向房地产房产表添加基本字段。
向表中添加以下基本字段:
字段 |
类型 |
|---|---|
name |
字符型 |
description |
文本 |
postcode |
字符型 |
date_availability |
日期 |
expected_price |
浮动 |
selling_price |
浮动 |
bedrooms |
整数 |
living_area |
整数 |
facades |
整数 |
garage |
布尔值 |
garden |
布尔值 |
garden_area |
整数 |
garden_orientation |
选择 |
garden_orientation 字段必须有 4 个可选值:’North’、’South’、’East’ 和 ‘West’。选择列表定义为一个元组列表,示例参见 此处。
将字段添加到模型后,使用 -u estate 重启服务器。
$ ./odoo-bin --addons-path=addons,../enterprise/,../tutorials/ -d rd-demo -u estate
连接到 psql 并检查表 estate_property 的结构。你会注意到表中还额外添加了几个字段。我们稍后会再讨论它们。
常用属性¶
注解
目标:本节结束时,表 estate_property 中的列 name 和 expected_price 应为非空:
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,默认值:字段名)字段在界面中显示的标签(用户可见)。
required(bool,默认值:False)如果为
True,则该字段不能为空。它必须具有默认值,或者在创建记录时始终被赋予一个值。help(str,默认值:'')在 UI 中为用户提供详细说明的提示信息。
index(bool,默认值:False)请求 Odoo 在该列上创建 database index。
练习
为现有字段设置属性。
添加以下属性:
字段 |
属性 |
|---|---|
name |
required |
expected_price |
required |
重启服务器后,这两个字段都应为非空。
自动字段¶
参考:本主题相关的文档可在 自动字段 中找到。
你可能已经注意到,你的模型中有几个从未定义过的字段。Odoo 会在所有模型中创建一些字段1。这些字段由系统管理,不能被写入,但如有需要,可以读取它们:
id(Id)模型中记录的唯一标识符。
create_date(Datetime)记录的创建日期。
create_uid(Many2one)创建该记录的用户。
write_date(Datetime)记录的最后修改日期。
write_uid(Many2one)最后修改该记录的用户。
既然我们已经创建了第一个模型,那就来 添加一些安全性 吧!
- 1
可以 禁用某些字段的自动创建
- 2
编写原生 SQL 查询是可行的,但需要谨慎,因为这会绕过 Odoo 的所有身份验证和安全机制。