第3章:模型与基本字段¶
At the end of the previous chapter, we were able to create an Odoo module. However, at this point it is still an empty shell which doesn’t allow us to store any data. In our real estate module, we want to store the information related to the properties (name, description, price, living area…) in a database. The Odoo framework provides tools to facilitate database interactions.
在继续练习之前,请确保已安装 estate
模块,即它必须在应用列表中显示为“已安装”。
警告
不要使用可变的全局变量。
A single Odoo instance can run several databases in parallel within the same python process. Distinct modules might be installed on each of these databases, therefore we cannot rely on global variables that would be updated depending on installed modules.
对象-关系映射¶
Reference: the documentation related to this topic can be found in the 模型 API.
注解
目标:在本节结束时,应创建表 estate_property
:
$ psql -d rd-demo
rd-demo=# SELECT COUNT(*) FROM estate_property;
count
-------
0
(1 row)
A key component of Odoo is the ORM layer. This layer avoids having to manually write most SQL and provides extensibility and security services2.
Business objects are declared as Python classes extending
Model
, which integrates them into the automated
persistence system.
Models can be configured by setting attributes in their
definition. The most important attribute is
_name
, which is required and defines the name for
the model in the Odoo system. Here is a minimum definition of a
model:
from odoo import models
class TestModel(models.Model):
_name = "test_model"
此定义已足够让 ORM 生成一个名为 test_model
的数据库表。按照约定,所有模型都位于 models
目录中,每个模型都在其自己的 Python 文件中定义。
请查看 crm_recurring_plan
表是如何定义的,以及对应的 Python 文件是如何被导入的:
The model is defined in the file
crm/models/crm_recurring_plan.py
(see here)The file
crm_recurring_plan.py
is imported incrm/models/__init__.py
(see here)The folder
models
is imported incrm/__init__.py
(see here)
Exercise
Define the real estate properties model.
Based on example given in the CRM module, create the appropriate files and folder for the
estate_property
table.
当文件创建完成后,为 estate.property
模型添加一个最小定义。
任何对 Python 文件的修改都需要重启 Odoo 服务器。当我们重启服务器时,我们将添加参数 -d
和 -u
:
$ ./odoo-bin --addons-path=addons,../enterprise/,../tutorials/ -d rd-demo -u estate
-u estate
means we want to upgrade the estate
module, i.e. the ORM will
apply database schema changes. In this case it creates a new table. -d rd-demo
means
that the upgrade should be performed on the rd-demo
database. -u
should always be used in
combination with -d
.
During the startup you should see the following warnings:
...
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...
...
If this is the case, then you should be good! To be sure, double check with psql
as demonstrated in
the Goal.
Exercise
Add a description.
Add a _description
to your model to get rid of one of the warnings.
模型字段¶
引用:有关此主题的文档可以在 字段 接口中找到。
字段用于定义模型可以存储什么内容以及存储的位置。字段在模型类中作为属性进行定义:
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
.
Types¶
注解
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
There are two broad categories of fields: ‘simple’ fields, which are atomic values stored directly in the model’s table, and ‘relational’ fields, which link records (of the same or different models).
Simple field examples are Boolean
, Float
,
Char
, Text
, Date
and Selection
.
Exercise
Add basic fields to the Real Estate Property table.
向表中添加以下基本字段:
字段 |
类型 |
---|---|
名称 |
字符 |
描述 |
Text |
邮编 |
字符 |
日期可用性 |
日期 |
预期价格 |
浮点数 |
销售价格 |
浮点数 |
卧室 |
整数 |
建筑面积 |
整数 |
facades |
整数 |
车库 |
布尔型 |
花园 |
布尔型 |
花园面积 |
整数 |
花园朝向 |
选择 |
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.
When the fields are added to the model, restart the server with -u estate
$ ./odoo-bin --addons-path=addons,../enterprise/,../tutorials/ -d rd-demo -u estate
Connect to psql
and check the structure of the table estate_property
. You’ll notice that
a couple of extra fields were also added to the table. We will revisit them later.
常见属性¶
注解
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 |
...
Much like the model itself, fields can be configured by passing configuration attributes as parameters:
name = fields.Char(required=True)
以下是一些可用于所有字段的常用属性:
string
(str
, default: field’s name)字段在用户界面中的标签(对用户可见)。
required`(``bool`
,默认:False
)If
True
, the field can not be empty. It must either have a default value or always be given a value when creating a record.help
(str
, default:''
)Provides long-form help tooltip for users in the UI.
index`(``bool`
,默认:False
)请求 Odoo 在该列上创建 数据库索引。
Exercise
Set attributes for existing fields.
Add the following attributes:
字段 |
属性 |
---|---|
名称 |
required |
预期价格 |
required |
After restarting the server, both fields should be not nullable.
Automatic Fields¶
Reference: the documentation related to this topic can be found in 自动字段.
You may have noticed your model has a few fields you never defined. Odoo creates a few fields in all models1. These fields are managed by the system and can’t be written to, but they can be read if useful or necessary:
id
(Id
)The unique identifier for a record of the model.
create_date
(日期时间
)记录的创建日期。
create_uid
(Many2one
)创建该记录的用户。
write_date
(Datetime
)记录的最后修改日期。
write_uid
(Many2one
)User who last modified the record.
Now that we have created our first model, let’s add some security!
- 1
可以 禁用某些字段的自动创建
- 2
writing raw SQL queries is possible, but requires caution as this bypasses all Odoo authentication and security mechanisms.