第 7 章:模型之间的关系¶
上一章 介绍了为包含基本字段的模型创建自定义视图。然而,在任何真实的业务场景中,我们需要的都不止一个模型。此外,模型之间的关联也是必不可少的。可以很容易地想象一个模型存放客户、另一个模型存放用户列表的情况。您可能需要在任何现有业务模型上引用某个客户或某个用户。
在房产模块中,我们希望房产包含以下信息:
购买该房产的客户
出售该房产的房地产经纪人
房产类型:独栋房屋、公寓、顶层复式、城堡……
描述房产特征的标签列表:温馨、已翻新……
收到的报价列表
Many2one¶
参考:与本主题相关的文档可参阅 Many2one。
Note
目标:在本节结束时:
应创建一个新的
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)
更多内容
在实践中,many2one 可以看作表单视图中的下拉列表。
Exercise
添加房产类型(Real Estate Property Type)表。
创建
estate.property.type模型并添加以下字段:
字段 |
类型 |
属性 |
|---|---|---|
name |
Char |
required |
按照本节 目标 中所示添加菜单
将字段
property_type_id添加到您的estate.property模型及其表单、列表和搜索视图中
这个练习是对前面各章的一个很好的回顾:您需要创建一个 模型,设置 模型,添加 动作和菜单,并 创建一个视图。
提示:不要忘记在 __init__.py 中导入任何新的 Python 文件,在 __manifest.py__ 中添加新的数据文件,也不要忘记添加访问权限 ;-)
再次重启服务器并刷新页面,看看结果吧!
在房产模块中,房产还缺少两项信息:买家和销售人员。买家可以是任何个人,而销售人员则必须是房产中介机构的员工(即 Odoo 用户)。
在 Odoo 中,我们通常会引用两个模型:
res.partner:合作伙伴是自然人或法人。可以是公司、个人,甚至是联系地址。res.users:系统的用户。用户可以是“内部用户”,即可以访问 Odoo 后端;也可以是“门户用户”,即无法访问后端,只能访问前端(例如在电子商务中查看自己以往的订单)。
Exercise
添加买家和销售人员。
使用上述两个常用模型,向 estate.property 模型添加买家和销售人员。它们应添加在表单视图的一个新选项卡中,如本节 目标 所示。
销售人员的默认值必须是当前用户。买家不应被复制。
提示:要获取默认值,请查看下方的注释,或参考 此处 的示例。
Note
对象 self.env 提供对请求参数以及其他有用内容的访问:
self.env.cr或self._cr是数据库 游标 对象;它用于查询数据库self.env.uid或self._uid是当前用户的数据库 idself.env.user是当前用户的记录self.env.context或self._context是上下文字典self.env.ref(xml_id)返回与 XML id 对应的记录self.env[model_name]返回给定模型的实例
现在让我们看看其他类型的关联。
Many2many¶
参考:与本主题相关的文档可参阅 Many2many。
Note
目标:在本节结束时:
应创建一个新的
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)
记录列表称为 记录集 (recordset),即记录的有序集合。它支持集合上的标准 Python 操作,例如 len() 和 iter(),还支持额外的集合运算,如 recs1 | recs2。
One2many¶
参考:与本主题相关的文档可参阅 One2many。
Note
目标:在本节结束时:
应创建一个新的
estate.property.offer模型,并配上相应的表单和列表视图。应向
estate.property模型添加报价:
在房产模块中,我们希望定义房产报价的概念。房产报价是潜在买家向卖家报出的金额。报价可以低于或高于预期价格。
一份报价适用于 一 个房产,但同一个房产可以有 多 份报价。这又一次体现了 many2one 概念。不过在本例中,我们希望显示给定房产的报价列表,因此将使用 one2many 概念。
one2many 是 many2one 的反向关联。例如,我们在测试模型上通过字段 partner_id 定义了指向 res.partner 模型的关联。我们可以定义其反向关联,即链接到该合作伙伴的测试模型列表::
test_ids = fields.One2many("test_model", "partner_id", string="Tests")
第一个参数称为 comodel,第二个参数则是要取其反向关联的字段。
按照惯例,one2many 字段带有 _ids 后缀。它们的行为如同一个记录列表,也就是说必须通过循环来访问数据::
for test in partner.test_ids:
print(test.name)
Danger
由于 One2many 是一种虚拟关联,comodel 中 必须 定义一个 Many2one 字段。
Exercise
添加房产报价(Real Estate Property Offer)表。
创建
estate.property.offer模型并添加以下字段:
字段 |
类型 |
属性 |
值 |
|---|---|---|---|
price |
Float |
||
status |
选择 |
不可复制 |
Accepted, Refused |
partner_id |
Many2one ( |
required |
|
property_id |
Many2one ( |
required |
创建一个列表视图和一个包含
price、partner_id和status字段的表单视图。无需创建动作或菜单。将字段
offer_ids添加到您的estate.property模型及其表单视图中,如本节 目标 所示。
这里有几个需要注意的重点。首先,并非所有模型都需要动作或菜单。有些模型旨在仅通过另一个模型访问。我们的练习正是这种情况:报价总是通过房产来访问。
其次,尽管 property_id 字段是必填的,我们并没有把它放进视图中。那么 Odoo 是如何知道我们的报价关联到哪个房产的呢?这正是 Odoo 框架的神奇之处:有些东西是隐式定义的。当我们通过 one2many 字段创建记录时,为方便起见,对应的 many2one 会被自动填充。
还活着吗?这一章确实不是最容易的一章。它在依赖此前所学全部内容的同时,引入了几个新概念。下一章 会轻松一些,别担心 ;-)