目录
概述
在介绍多对多关系之前,我们先补上上一篇文章缺失的一部分代码
在房地产模块中,我们仍然缺少关于房产的两项信息:买方partner和销售人员salesperson。买方可以是任何个人,但另一方面,销售人员必须是房地产公司的员工(即 Odoo 用户)。
在 Odoo 中,我们有两个模型model我们是经常用到的:
res.partner:合作伙伴是一个物理或法律实体。它可以是公司、个人,甚至是一个联系地址。
res.users:系统用户。用户可以是 "内部 "用户,即他们可以访问 Odoo 后台。也可以是 "门户 "用户,即他们不能访问后台,只能访问前台(例如,在电子商务中访问他们以前的订单)。
下面给我们的estate_property模型加上:
user_id = fields.Many2one("res.users", string="Salesperson", default=lambda self: self.env.user)
partner_id = fields.Many2one("res.partner", string="Partner", copy=False)
注意user_id的默认值必须是当前用户。合作伙伴应该不能被复制。
备注
- 对象 self.env 允许访问请求参数和其他有用信息:
- self.env.cr 或 self._cr 是数据库游标对象;用于查询数据库
- self.env.uid 或 self._uid 是当前用户的数据库 ID
- self.env.user 是当前用户的记录
- self.env.context 或 self._context 是上下文字典
- self.env.ref(xml_id) 返回 XML id 对应的记录
- self.env[model_name] 返回给定模型的实例
Many2many多对多关系
在房地产模块中,我们要定义房产标签的概念。例如,"舒适 "或 "装修 "的房产就是房产标签。
一个房产可以有多个标签,一个标签可以分配给多个房产。这可以通过 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。
添加房地产属性标签表
class EstatePropertyTag(models.Model):
_name = "estate_property_tag"
_description = "Estate Property Tag"
name = fields.Char(required=True)
提示:在视图中,使用 widget="many2many_tags" 属性,如以下代码所示。widget 属性将在后面的培训章节中详细讲解。现在,你可以尝试添加或删除它,看看效果如何;-)
我们现在新增了settings菜单。
还在房产的详情中新增了tag_ids(毛坯,精装修)
代码实践
以下是我们现在的estate_property_views.xml的完整代码:
<?xml version="1.0"?>
<odoo>
<record id="estate_property_action" model="ir.actions.act_window">
<field name="name">房产列表</field>
<field name="res_model">estate_property</field>
<field name="view_mode">tree,form</field>
</record>
<record id="estate_property_type_action" model="ir.actions.act_window">
<field name="name">房产类型</field>
<field name="res_model">estate_property_type</field>
<field name="view_mode">tree,form</field>
</record>
<record id="estate_property_tag_action" model="ir.actions.act_window">
<field name="name">房产标签</field>
<field name="res_model">estate_property_tag</field>
<field name="view_mode">tree,form</field>
</record>
<record id="estate_property_view_tree" model="ir.ui.view">
<field name="name">房产列表</field>
<field name="model">estate_property</field>
<field name="arch" type="xml">
<tree string="房产列表">
<field name="name"/>
<field name="bedrooms"/>
<field name="living_area"/>
<field name="expected_price"/>
<field name="selling_price"/>
<field name="date_available"/>
</tree>
</field>
</record>
<record id="estate_property_view_form" model="ir.ui.view">
<field name="name">房产详情</field>
<field name="model">estate_property</field>
<field name="arch" type="xml">
<form string="详情">
<sheet>
<div class="oe_title">
<h1>
<field name="name"/>
</h1>
</div>
<field name="tag_ids" widget="many2many_tags"/>
<group name="estate_property_header">
<group name="estate_property_details">
<group col="2">
<field name="property_type_id"/>
<field name="postcode"/>
<field name="expected_price"/>
</group>
<group col="2">
<field name="date_available"/>
<field name="selling_price"/>
</group>
</group>
<notebook>
<page string="Description">
<group name="estate_property_details">
<field name="description"/>
<field name="bedrooms"/>
<field name="living_area"/>
<field name="facades"/>
<field name="garage"/>
<field name="garden_area"/>
<field name="garden_orientation"/>
<field name="state"/>
</group>
</page>
<page string="Other info">
<group name="estate_property_details">
<field name="user_id"/>
<field name="partner_id"/>
</group>
</page>
</notebook>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_estate_property_search" model="ir.ui.view">
<field name="name">estate_property</field>
<field name="model">estate_property</field>
<field name="arch" type="xml">
<search string="estate_property">
<field name="bedrooms" />
<field name="postcode" />
<field name="living_area" />
<field name="property_type_id" />
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
<filter string="New or Offer Accepted" name="new_offer_accepted" domain="[('state', 'in', ['new', 'offer_accepted'])]"/>
<group expand="1" string="Group By">
<filter string="邮编分组" name="postcode" context="{'group_by':'postcode'}"/>
</group>
</search>
</field>
</record>
</odoo>
我们的model模型文件estate_property.py的完整代码如下:
from odoo import models, fields, api
from dateutil.relativedelta import relativedelta
class EstateProperty(models.Model):
_name = "estate_property"
_description = "Estate Property"
def _get_default_date_available(self):
# 使用 fields.Date.today() 获取当前日期,并添加三个月
return fields.Date.today() + relativedelta(months=+3)
name = fields.Char(required=True, default="Unknown")
description = fields.Text()
postcode = fields.Char()
date_available = fields.Date(copy=False, default=_get_default_date_available)
expected_price = fields.Float(required=True)
selling_price = fields.Float(readonly=True, copy=False)
bedrooms = fields.Integer()
living_area = fields.Integer()
facades = fields.Integer() # 外墙
garage = fields.Boolean()
garden = fields.Boolean()
garden_area = fields.Integer()
garden_orientation = fields.Selection([
("north", "North"),
("south", "South"),
("east", "East"),
("west", "West"),
])
active = fields.Boolean(default=True)
state = fields.Selection([
("new", "New"),
("offer_received", "Offer Received"),
("offer_accepted", "Offer Accepted"),
("sold", "Sold"),
("canceled", "Canceled"),
], default="new", copy=False)
property_type_id = fields.Many2one("estate_property_type", string="Property Type")
user_id = fields.Many2one("res.users", string="Salesperson", default=lambda self: self.env.user)
partner_id = fields.Many2one("res.partner", string="Partner", copy=False)
tag_ids = fields.Many2many("estate_property_tag", string="Tags")
class EstatePropertyType(models.Model):
_name = "estate_property_type"
_description = "Estate Property Type"
name = fields.Char(required=True)
class EstatePropertyTag(models.Model):
_name = "estate_property_tag"
_description = "Estate Property Tag"
name = fields.Char(required=True)
根据之前文章所学的知识,自己修改estate_menus.xml和ir.model.access.csv以达到添加菜单的目的,快自己试试吧!