第 7 章:模型之间的关系

在( 上一章 )涵盖了为包含基本字段的模型创建自定义视图的内容。然而,在任何实际业务场景中,我们不仅需要一个模型,还需要模型之间的关联。可以很容易想象,一个模型包含客户信息,另一个模型包含用户列表。在任何现有的业务模型中,您可能都需要引用客户或用户。

在我们的房地产模块中,我们希望为房产添加以下信息:

  • 购买房产的客户

  • 出售房产的房地产代理

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

  • 描述房产的一组标签:舒适、翻新……

  • 收到的报价列表

多对一(Many2one)

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

注解

目标:在本节结束时:

  • 应创建一个新的 estate.property.type 模型,并为其添加相应的菜单、操作和视图。

房产类型
  • 应在 estate.property 模型中添加三个多对一字段:房产类型、买家和卖家。

房产

在我们的房地产模块中,我们需要定义“房产类型”的概念。例如,房产类型可以是房屋或公寓。根据类型对房产进行分类是一项标准的业务需求,尤其是为了优化过滤功能。

一个房产只能有一个类型,但同一类型可以分配给多个房产。这由“多对一”(many2one)概念支持。

多对一是指向另一个对象的简单链接。例如,为了在测试模型中定义与 res.partner 的链接,我们可以写::

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

按照惯例,多对一字段带有 _id 后缀。然后可以通过以下方式轻松访问合作伙伴中的数据::

print(my_test_object.partner_id.name)

参见

外键

实际上,多对一字段在表单视图中表现为一个下拉列表。

Exercise

添加房地产属性类型表。

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

字段

类型

属性

名称

字符

依赖

  • 按照本节 目标 中显示的内容添加菜单。

  • estate.property 模型及其表单视图、列表视图和搜索视图中添加字段 property_type_id

本练习是对前面章节的良好回顾:您需要创建一个 模型 ,设置 模型权限 ,添加 操作和菜单 ,并 创建视图

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

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

在房地产模块中,我们仍缺少两项关于房产的信息:买家和销售人员。买家可以是任何个人,但另一方面,销售人员必须是房地产机构的员工(即Odoo用户)。

在Odoo中,我们通常会引用两个模型:

  • res.partner :合作伙伴是一个物理或法律实体。它可以是公司、个人,甚至是联系地址。

  • res.users :系统用户。用户可以是“内部用户”,即他们可以访问Odoo后台;或者他们是“门户用户”,即无法访问后台,只能访问前端(例如,在电子商务中查看之前的订单)。

Exercise

添加买家和销售人员。

使用上述两个常见模型将买家和销售人员添加到 estate.property 模型中。它们应添加到表单视图的新选项卡中,如本节 目标 所示。

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

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

注解

对象 self.env 提供对请求参数和其他有用内容的访问:

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

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

  • self.env.user 是当前用户的记录

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

  • self.env.ref(xml_id) 返回与 XML ID 对应的记录

  • self.env[model_name] 返回给定模型的实例

现在让我们来看看其他类型的关联。

多对多(Many2many)

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

注解

目标:在本节结束时:

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

房产标签
  • 应在 estate.property 模型中添加标签:

房产

在我们的房地产模块中,我们需要定义“房产标签”的概念。例如,一个房产可以是“舒适”或“翻新”。

一个房产可以有 多个 标签,而一个标签也可以分配给 多个 房产。这由“多对多”( many2many )概念支持。

多对多是一种双向多对多关系:一侧的任何记录都可以与另一侧的任意数量的记录相关联。例如,为了在测试模型中定义与 account.tax 模型的链接,我们可以写::

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

按照惯例,多对多字段带有 _ids 后缀。这意味着可以将多个税项添加到我们的测试模型中。它表现为一个记录列表,因此访问数据必须在循环中完成::

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

记录列表被称为 记录集 (recordset),即一个有序的记录集合。它支持标准的Python集合操作,如 len()iter() ,以及额外的集合操作,如 recs1 | recs2

Exercise

添加房地产属性标签表。

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

字段

类型

属性

名称

字符

依赖

  • 按照本节 目标 中显示的内容添加菜单。

  • estate.property 模型及其表单和列表视图中添加字段 tag_ids

提示:在视图中,使用 widget="many2many_tags" 属性,如 此处 所示。widget 属性将在培训的 后续章节 中详细说明。现在,您可以尝试添加或移除它并查看结果 ;-)

一对多(One2many)

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

注解

目标:在本节结束时:

  • 应创建一个新的 estate.property.offer 模型,并为其添加相应的表单视图和列表视图。

  • 应在 estate.property 模型中添加报价:

房产报价

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

一个报价适用于 一个 房产,但同一房产可以有 多个 报价。“多对一”( many2one )概念再次出现。然而,在这种情况下,我们希望显示特定房产的报价列表,因此我们将使用“一对多”( one2many )概念。

一对多是多对一的反向关系。例如,我们在测试模型中通过字段 partner_id 定义了与 res.partner 模型的链接。我们可以定义反向关系,即与我们的合作伙伴相关的测试模型列表::

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

第一个参数称为 comodel (关联模型),第二个参数是我们要反向关联的字段。

按照惯例,一对多字段带有 _ids 后缀。它们表现为一个记录列表,因此访问数据必须在循环中完成::

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

危险

由于 One2many 是一种虚拟关系,因此在关联模型中 必须 定义一个 Many2one 字段。

Exercise

添加房地产属性报价表。

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

字段

类型

属性

值(Values)

价格

Float

状态

选择

不复制

Accepted, Refused

客户ID

Many2one (res.partner)

依赖

属性ID

多对一(estate.property

依赖

  • 使用 pricepartner_idstatus 字段创建列表视图和表单视图。无需创建操作或菜单。

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

这里有几点需要注意。首先,并非所有模型都需要操作或菜单。某些模型只能通过其他模型访问。在我们的练习中就是这种情况:报价始终通过房产访问。

其次,尽管 property_id 字段是必填项,我们并未将其包含在视图中。那么 Odoo 如何知道我们的报价与哪个属性相关联呢?这就是使用 Odoo 框架的魔力之一:有时事情是隐式定义的。当我们通过一对多字段创建记录时,为了方便起见,对应的多对一字段会自动填充。

还活着吗?本章绝对不是最简单的。它引入了一些新概念,同时依赖于之前介绍的所有内容。别担心, 下一章 会轻松一些 ;-)