第 11 章:添加点缀

我们的房地产模块从商业角度来看现在已初具雏形。我们创建了 特定视图 ,添加了多个 操作按钮约束条件 。然而,我们的用户界面仍然有些粗糙。我们希望为列表视图添加一些颜色,并让某些字段和按钮根据条件隐藏。例如,“已售出”和“取消”按钮在房产状态为已售或已取消时应消失,因为此时不再允许更改状态。

本章仅涵盖视图功能的一小部分。如需更全面的概述,请随时查阅参考文档。

参考:与本章相关的文档可以在 视图记录视图架构 中找到。

内联视图

注解

目标:在本节结束时,应在房产类型视图中添加特定的房产列表:

内联列表视图

在房地产模块中,我们为房产添加了一个报价列表。我们只需通过以下方式添加字段 offer_ids

<field name="offer_ids"/>

该字段使用了 estate.property.offer 的特定视图。在某些情况下,我们需要定义一个仅在表单视图上下文中使用的特定列表视图。例如,我们希望显示与房产类型关联的房产列表。不过,为了清晰起见,我们只想显示 3 个字段:名称、预期价格和状态。

为此,我们可以定义 内联 列表视图。内联列表视图直接定义在表单视图内部。例如:

from odoo import fields, models

class TestModel(models.Model):
    _name = "test_model"
    _description = "Test Model"

    description = fields.Char()
    line_ids = fields.One2many("test_model_line", "model_id")


class TestModelLine(models.Model):
    _name = "test_model_line"
    _description = "Test Model Line"

    model_id = fields.Many2one("test_model")
    field_1 = fields.Char()
    field_2 = fields.Char()
    field_3 = fields.Char()
<form>
    <field name="description"/>
    <field name="line_ids">
        <list>
            <field name="field_1"/>
            <field name="field_2"/>
        </list>
    </field>
</form>

test_model 的表单视图中,我们为 test_model_line 定义了一个特定的列表视图,包含字段 field_1field_2

可以在此处找到示例: 这里

Exercise

添加内联列表视图。

  • estate.property.type 模型添加 One2many 字段 property_ids

  • 将字段添加到 estate.property.type 的表单视图中,如本节 目标 中所示。

部件

参考:与本节相关的文档可以在 字段 中找到。

注解

目标:在本节结束时,房产状态应使用特定的小部件显示:

状态栏小部件

显示四种状态:新建、收到报价、接受报价和已售出。

每当我们向模型添加字段时,几乎不需要担心这些字段在用户界面中的外观。例如, Date 字段会提供日期选择器,而 One2many 字段会自动显示为列表。Odoo 会根据字段类型选择合适的“小部件”。

然而,在某些情况下,我们需要特定的字段表示形式,这可以通过 widget 属性实现。我们已经在 tag_ids 字段中使用过它,当时我们使用了 widget="many2many_tags" 属性。如果我们没有使用它,那么该字段将显示为列表。

每种字段类型都有一组小部件,可用于微调其显示效果。一些小部件还支持额外选项。完整列表请参阅 字段

Exercise

使用状态栏小部件。

使用 statusbar 小部件以显示 estate.propertystate,如本节的 目标 所示。

提示:可以在此处找到一个简单示例:链接

警告

在同一视图中多次出现相同字段

只能将字段 一次 添加到列表或表单视图中。不支持多次添加。

列表排序

参考:与本节相关的文档可以在 模型 中找到。

注解

目标:在本节结束时,所有列表应默认以确定性顺序显示。房产类型可以手动排序。

在之前的练习中,我们创建了多个列表视图。然而,我们从未指定记录的默认排序方式。这对于许多业务场景来说非常重要。例如,在我们的房地产模块中,我们可能希望将最高报价显示在列表顶部。

模型

Odoo 提供了几种设置默认排序的方法。最常见的方法是直接在模型中定义 _order 属性。这样,检索到的记录将遵循一个确定性的排序,并且在所有视图(包括通过程序搜索记录时)中保持一致。默认情况下未指定排序,因此记录将以依赖于 PostgreSQL 的非确定性顺序检索。

_order 属性接受一个包含字段列表的字符串,这些字段将用于排序。它会被转换为 SQL 中的 order_by 子句。例如:

from odoo import fields, models

class TestModel(models.Model):
    _name = "test_model"
    _description = "Test Model"
    _order = "id desc"

    description = fields.Char()

我们的记录按 id 降序排列,这意味着最大的记录排在最前面。

Exercise

添加模型排序。

在对应的模型中定义以下排序顺序:

模型

排序

estate.property

按 ID 降序

estate.property.offer

按价格降序

estate.property.tag

名称

estate.property.type

名称

视图

可以在模型级别进行排序。这种方法的优点是无论在哪检索记录列表,排序都是一致的。然而,也可以通过视图中的 default_order 属性直接定义特定的排序( 示例 )。

手动

模型和视图排序都能在记录排序时提供灵活性,但还有一种情况需要覆盖:手动排序。用户可能希望根据业务逻辑对记录进行排序。例如,在我们的房地产模块中,我们可能希望手动对房产类型进行排序。让最常用的类型出现在列表顶部确实很有用。如果我们的房地产机构主要销售房屋,那么让“房屋”排在“公寓”之前会更方便。

为此,可以结合使用 sequence 字段和 handle 小部件。显然, sequence 字段必须是 _order 属性中的第一个字段。

Exercise

添加手动排序。

  • 添加以下字段:

模型

字段

类型

estate.property.type

顺序

整数

  • 将序列添加到 estate.property.type 列表视图中,并使用正确的小部件。

提示:您可以在此处找到示例:模型视图

属性与选项

详细说明所有可用于微调视图外观的功能将会非常繁琐。因此,我们将专注于最常见的功能。

表单

注解

目标:在本节结束时,房产表单视图将具有以下内容:

  • 按钮和字段的条件显示

  • 标签颜色

带有点缀的表单视图

在我们的房地产模块中,我们希望修改某些字段的行为。例如,我们不希望通过表单视图创建或编辑房产类型。相反,我们期望在适当的菜单中管理类型。此外,我们还希望为标签添加颜色。为了实现这些行为定制,我们可以为多个字段小部件添加 options 属性。

Exercise

添加小部件选项。

  • property_type_id 字段添加适当的选项,以防止从属性表单视图中创建或编辑属性类型。请查看 Many2one 小部件文档 以获取更多信息。

  • 添加以下字段:

模型

字段

类型

estate.property.tag

颜色

整数

然后为 tag_ids 字段添加适当的选项,以便在标签上添加颜色选择器。请查看 FieldMany2ManyTags 小部件文档 以获取更多信息。

第 5 章:终于,可以玩转一些用户界面(UI)了 中,我们看到保留字段被用于特定行为。例如,active 字段用于自动过滤掉非活动记录。我们也添加了 state 作为保留字段。现在是时候使用它了! state 字段可以与视图中的 invisible 属性结合使用,以实现按钮的条件显示。

Exercise

添加按钮的条件显示。

使用 invisible 属性按条件显示头部按钮,如本节 目标 中所示(注意当状态更改时,“已售出”和“取消”按钮如何变化)。

提示:不妨在 Odoo 的 XML 文件中搜索 invisible= 以找到一些示例。

更广泛地说,可以根据其他字段的值使字段变为 invisible (不可见)、 readonly (只读)或 required (必填)。请注意, invisible 也可以应用于视图中的其他元素,例如 buttongroup

invisiblereadonlyrequired 可以接受任何 Python 表达式作为值。该表达式指定了属性生效的条件。例如:

<form>
    <field name="description" invisible="not is_partner"/>
</form>

这意味着当 is_partnerFalse 时, description 字段将不可见。需要注意的是,用于 invisible 的字段 必须 出现在视图中。如果它不应该向用户显示,我们可以使用 invisible 属性将其隐藏。

Exercise

使用 invisible

  • estate.property 表单视图中,当没有花园时,将花园面积和方向设置为不可见。

  • 一旦报价状态被设置,将“接受”和“拒绝”按钮设置为不可见。

  • 当属性状态为“报价已接受”、“已售出”或“已取消”时,不允许添加报价。为此,请使用 readonly 属性。

警告

在视图中使用(条件性) readonly 属性可以有效防止数据输入错误,但请记住,它并不提供任何安全性!服务器端不会进行检查,因此始终可以通过 RPC 调用写入该字段。

列表

注解

目标:在本节结束时,房产和报价列表视图应具有颜色装饰。此外,报价和标签将可以直接在列表中编辑,而可用日期将默认隐藏。

带有装饰和可选字段的列表视图 可编辑列表

当模型只有少量字段时,直接通过列表视图编辑记录而不打开表单视图可能会很有用。在房地产示例中,无需打开表单视图即可添加报价或创建新标签。这可以通过 editable 属性实现。

Exercise

使列表视图可编辑。

使 estate.property.offerestate.property.tag 列表视图可编辑。

另一方面,当模型包含大量字段时,可能会倾向于在列表视图中添加过多字段,从而使视图变得不清晰。一种替代方法是添加这些字段,但使它们可以选择性隐藏。这可以通过使用 optional 属性实现。

Exercise

使字段可选。

使 estate.property 列表视图中的字段 date_availability 可选并默认隐藏。

最后,颜色代码对于视觉上突出显示记录非常有用。例如,在房地产模块中,我们希望将被拒绝的报价显示为红色,将接受的报价显示为绿色。这可以通过 decoration-{$name} 属性实现(完整列表请参见 字段 ):

<list decoration-success="is_partner==True">
    <field name="name"/>
</list>

其中 is_partnerTrue 的记录将以绿色显示。

Exercise

添加一些装饰。

estate.property 列表视图中:

  • 已收到报价的属性显示为绿色

  • 已接受报价的属性显示为绿色且加粗

  • 已售出的属性显示为低调(灰色)

estate.property.offer 列表视图中:

  • 被拒绝的报价显示为红色

  • 被接受的报价显示为绿色

  • 状态字段应不再可见

提示:

  • 请记住,属性中使用的所有字段都必须存在于视图中!

  • 如果要测试“已收到报价”和“已接受报价”状态的颜色,请将字段添加到表单视图中并手动更改它(我们稍后会实现其业务逻辑)。

统计按钮

注解

目标:在本节结束时,房产类型表单视图上将有一个统计按钮,点击后会显示与该类型房产相关的所有报价列表。

统计按钮

如果您已经在 Odoo 中使用过一些功能模块,可能已经遇到过“统计按钮”。这些按钮显示在表单视图的右上角,提供对关联文档的快速访问。在我们的房地产模块中,我们希望有一个快速链接,指向与特定房产类型相关的报价,如本节的 目标 所述。

在教程的这个阶段,我们已经了解了完成此操作的大部分概念。然而,解决方案并非唯一,如果您不知道从哪里开始,仍然可能会感到困惑。我们将在练习中描述一个逐步解决方案。通过在 Odoo 代码库中搜索 oe_stat_button 来寻找示例总是很有用的。

以下练习可能比之前的练习稍微困难一些,因为它假设您能够自行在源代码中查找示例。如果您卡住了,附近可能有人可以帮助您 ;-)

本练习介绍了 关联字段 的概念。理解它的最简单方法是将其视为计算字段的一种特殊情况。以下是 description 字段的定义:

...

partner_id = fields.Many2one("res.partner", string="Partner")
description = fields.Char(related="partner_id.name")

等价于:

...

partner_id = fields.Many2one("res.partner", string="Partner")
description = fields.Char(compute="_compute_description")

@api.depends("partner_id.name")
def _compute_description(self):
    for record in self:
        record.description = record.partner_id.name

每当合作伙伴名称更改时,描述也会随之修改。

Exercise

为属性类型添加统计按钮。

  • 将字段 property_type_id 添加到 estate.property.offer 中。我们可以将其定义为 property_id.property_type_id 的关联字段,并将其设置为存储字段。

通过该字段,在创建报价时,报价将与属性类型相关联。您可以将该字段添加到报价的列表视图中以确保其正常工作。

  • 将字段 offer_ids 添加到 estate.property.type 中,这是上一步中定义字段的反向 One2many 字段。

  • 将字段 offer_count 添加到 estate.property.type 中。这是一个计算字段,用于统计特定属性类型的报价数量(使用 offer_ids 来实现)。

此时,您已经拥有所有必要的信息来了解有多少报价与某个属性类型相关联。如果有疑问,可以直接将 offer_idsoffer_count 添加到视图中。下一步是单击统计按钮时显示列表。

  • estate.property.type 上创建一个指向 estate.property.offer 动作的统计按钮。这意味着您应该使用 type="action" 属性(如果需要复习,请返回查看 第 9 章:准备好迎接一些操作了吗? 的结尾部分)。

此时,单击统计按钮应显示所有报价。我们仍然需要对报价进行过滤。

  • estate.property.offer 动作中,添加一个域条件,将 property_type_id 定义为等于 active_id (即当前记录, 这里有一个示例

看起来不错?如果还没有,别担心,下一章 不需要统计按钮 ;-)