第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 文件是如何被导入的:

  1. The model is defined in the file crm/models/crm_recurring_plan.py (see here)

  2. The file crm_recurring_plan.py is imported in crm/models/__init__.py (see here)

  3. The folder models is imported in crm/__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.