Chapter 7: Relations Between Models

The previous chapter covered the creation of custom views for a model containing basic fields. However, in any real business scenario we need more than one model. Moreover, links between models are necessary. One can easily imagine one model containing the customers and another one containing the list of users. You might need to refer to a customer or a user on any existing business model.

在我们的房地产模块中,我们需要以下有关房产的信息:

  • 购买该物业的客户

  • 售出该物业的房地产经纪人

  • 物业类型:房屋、公寓、顶层公寓、城堡…

  • 一个描述该物业的标签列表:舒适,翻新…

  • 收到的报价清单

多对一

参考: 与此主题相关的文档可以在 Many2one 中找到。

注解

目标:在本节结束时:

  • 应该创建一个新的 estate.property.type 模型,并配备相应的菜单、操作和视图。

属性类型
  • 应该在 estate.property 模型中添加三个 Many2one 字段:物业类型、买家和卖家。

属性

在我们的房地产模块中,我们想要定义物业类型的概念。物业类型可以是房屋或公寓等。根据物业类型对物业进行分类是标准的业务需求,特别是为了精细化过滤。

一个属性只能有 一个 类型,但是同一种类型可以分配给 多个 属性。这是由 many2one 概念支持的。

many2one 是一个简单的链接到另一个对象。例如,为了在我们的测试模型中定义到 res.partner 的链接,我们可以编写如下代码::

partner_id = fields.Many2one("res.partner", string="Partner")

按照惯例,many2one 字段具有 _id 后缀。然后可以轻松地使用以下方式访问合作伙伴中的数据:

print(my_test_object.partner_id.name)

另请参阅

foreign keys

在实践中,many2one 可以在表单视图中看作是一个下拉列表。

Exercise

添加房地产物业类型表。

  • 创建 estate.property.type 模型并添加以下字段:

字段

类型

属性

名称

字符

必填

  • 按照本节的 目标 显示的方式添加菜单

  • Add the field property_type_id into your estate.property model and its form, list and search views

This exercise is a good recap of the previous chapters: you need to create a model, set the model, add an action and a menu, and create a view.

提示:不要忘记在 __init__.py 中导入任何新的 Python 文件,在 __manifest.py__ 中添加新的数据文件或添加访问权限;-)

再次重启服务器并刷新以查看结果!

在房地产模块中,我们仍然需要两个缺失的信息:买家和销售人员。买家可以是任何个人,但销售人员必须是房地产机构的员工(即Odoo用户).

在Odoo中,我们通常提到两个模型:

  • res.partner: a partner is a physical or legal entity. It can be a company, an individual or even a contact address.

  • res.users: the users of the system. Users can be ‘internal’, i.e. they have access to the Odoo backend. Or they can be ‘portal’, i.e. they cannot access the backend, only the frontend (e.g. to access their previous orders in eCommerce).

Exercise

添加买家和销售人员。

使用上述两个常见模型向 estate.property 模型添加一个买家和一个销售员。它们应该在表单视图的一个新标签中添加,如本节的 目标 所示。

销售员的默认值必须是当前用户。不应复制买方。

提示:要获取默认值,请查看下面的注释或查看示例 这里.

注解

对象 self.env 提供了访问请求参数和其他有用信息的方法:

  • self.env.crself._cr 是数据库 cursor 对象;它用于查询数据库

  • self.env.uidself._uid 是当前用户的数据库ID

  • self.env.user is the current user’s record

  • self.env.contextself._context 是上下文字典

  • self.env.ref(xml_id) returns the record corresponding to an XML id

  • self.env[model_name] returns an instance of the given model

现在让我们来看看其他类型的链接。

多对多

参考: 与此主题相关的文档可以在 Many2many 中找到。

注解

目标:在本节结束时:

  • 应创建一个新的 estate.property.tag 模型,并创建相应的菜单和操作。

属性标签
  • 应该将标签添加到 estate.property 模型中:

属性

在我们的房地产模块中,我们想要定义物业标签的概念。物业标签是指,例如,一个被称为“舒适”的物业或“翻新”的物业。

一个属性可以有 多个 标签,一个标签也可以被分配给 多个 属性。这是由 many2many 概念支持的。

many2many 是一个双向多对多关系:一边的任何记录都可以与另一边的任意数量的记录相关联。例如,在我们的测试模型上定义与 account.tax 模型的链接,我们可以编写如下代码:

tax_ids = fields.Many2many("account.tax", string="Taxes")

按照惯例,many2many 字段具有 _ids 后缀。这意味着可以向我们的测试模型添加多个税。它的行为类似于记录列表,这意味着访问数据必须在循环中完成:

for tax in my_test_object.tax_ids:
    print(tax.name)

一组记录被称为 记录集 ,即有序的记录集合。它支持对集合进行标准的Python操作,如 len()iter() ,还支持额外的集合操作,如 recs1 | recs2

Exercise

添加房地产属性标签表。

  • 创建 estate.property.tag 模型并添加以下字段:

字段

类型

属性

名称

字符

必填

  • 按照本节的 目标 显示的方式添加菜单

  • Add the field tag_ids to your estate.property model and in its form and list views

Tip: in the view, use the widget="many2many_tags" attribute as demonstrated here. The widget attribute will be explained in detail in a later chapter of the training. For now, you can try to adding and removing it and see the result ;-)

一对多

参考: 与此主题相关的文档可以在 One2many 中找到。

注解

目标:在本节结束时:

  • a new estate.property.offer model should be created with the corresponding form and list view.

  • 应该将报价添加到 estate.property 模型中:

物业出售

在我们的房地产模块中,我们想定义房产报价的概念。房产报价是潜在买家向卖家提供的金额。报价可能低于或高于预期价格。

一个房产只能有 一个 报价,但是同一个房产可以有 多个 报价。再次出现了 many2one 的概念。然而,在这种情况下,我们想要显示给定房产的报价列表,所以我们将使用 one2many 的概念。

一个 one2many 是 many2one 的反向关系。例如,我们在我们的测试模型上定义了一个链接到 res.partner 模型的字段 partner_id。我们可以定义反向关系,即与我们的合作伙伴关联的测试模型列表:

test_ids = fields.One2many("test_model", "partner_id", string="Tests")

第一个参数被称为 comodel,第二个参数是我们想要反转的字段。

按照惯例,one2many字段具有 _ids 后缀。它们的行为类似于记录列表,这意味着访问数据必须在循环中完成:

for test in partner.test_ids:
    print(test.name)

危险

Because a One2many is a virtual relationship, there must be a Many2one field defined in the comodel.

Exercise

添加房地产物业报价表。

  • 创建 estate.property.offer 模型并添加以下字段:

字段

类型

属性

价格

浮点数

状态

选择

无复制

已接受,已拒绝

合作伙伴ID

Many2one (res.partner)

必填

属性ID

Many2one (estate.property)

必填

  • Create a list view and a form view with the price, partner_id and status fields. No need to create an action or a menu.

  • 将字段 offer_ids 添加到您的 estate.property 模型中,并在其表单视图中按照本节的 目标 所示。

这里有几个重要的事情需要注意。首先,我们不需要为所有模型创建操作或菜单。有些模型只能通过另一个模型访问。这是我们练习中的情况:一个报价总是通过一个属性访问。

其次,尽管 property_id 字段是必需的,但我们没有在视图中包含它。那么Odoo如何知道我们的报价与哪个物业相关联呢?这就是使用Odoo框架的魔力的一部分:有时事情是隐含定义的。当我们通过one2many字段创建记录时,相应的many2one字段会自动填充以方便使用。

Still alive? This chapter is definitely not the easiest one. It introduced a couple of new concepts while relying on everything that was introduced before. The next chapter will be lighter, don’t worry ;-)