第12章:添加彩色糖屑

我们的房地产模块现在从商业角度来看是有意义的。我们创建了 特定视图 ,添加了几个 操作按钮约束 。然而,我们的用户界面还有些粗糙。我们想要为列表视图添加一些颜色,并使一些字段和按钮在特定条件下消失。例如,当房产被售出或取消时,’已售’和’取消’按钮应该消失,因为此时不再允许更改状态。

本章节仅涵盖了视图中的一小部分功能。请阅读参考文档以获取更全面的概述。

参考: 本章相关的文档可以在 视图 中找到。

内联视图

注解

目标:在本节结束时,应该向属性类型视图中添加一个特定的属性列表:

内联列表视图

在房地产模块中,我们为一个属性添加了一个报价列表。我们只需添加字段 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">
        <tree>
            <field name="field_1"/>
            <field name="field_2"/>
        </tree>
    </field>
</form>

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

一个例子可以在 这里 找到。

Exercise

添加一个内联列表视图。

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

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

小部件

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

注解

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

状态栏小部件

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

无论我们向模型中添加了哪些字段,我们(几乎)从来不需要担心这些字段在用户界面中的显示方式。例如,对于 Date 字段,提供了一个日期选择器,而 One2many 字段则自动显示为一个列表。Odoo根据字段类型选择合适的“小部件”。

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

每个字段类型都有一组小部件,可以用来微调其显示。有些小部件还可以使用额外的选项。详细列表请参见: 字段小部件

Exercise

使用状态栏小部件。

使用 statusbar 小部件来显示 estate.propertystate,如本节的 Goal 所示。

提示:一个简单的例子可以在 这里 找到。

警告

在视图中多次使用同一字段

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

订单列表

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

注解

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

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

模型

Odoo 提供了几种设置默认顺序的方法。最常见的方法是直接在模型中定义 _order 属性。这样,检索到的记录将遵循确定性顺序,在所有视图中都是一致的,包括在编程搜索记录时。默认情况下,没有指定顺序,因此记录将以非确定性顺序检索,这取决于 PostgreSQL。

The _order attribute takes a string containing a list of fields which will be used for sorting. It will be converted to an order_by clause in SQL. For example:

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

名称

View

在模型级别上可以进行排序。这样做的好处是在检索记录列表时,可以保持一致的顺序。然而,也可以通过视图直接定义特定的顺序,这要归功于``default_order``属性(示例)。

手动

模型和视图排序都允许在排序记录时灵活处理,但仍有一种情况需要考虑:手动排序。用户可能希望根据业务逻辑对记录进行排序。例如,在我们的房地产模块中,我们希望手动对房地产类型进行排序。确实有用的是将最常用的类型显示在列表的顶部。如果我们的房地产代理主要销售房屋,则将“House”放在“Apartment”之前更为方便。

要做到这一点,需要将 sequence 字段与 handle 小部件结合使用。显然, sequence 字段必须是 _order 属性中的第一个字段。

Exercise

添加手动排序。

  • 添加以下字段:

模型

字段

类型

estate.property.type

序列

整数

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

提示:你可以在这里找到一个例子: model <https://github.com/odoo/odoo/blob/892dd6860733c46caf379fd36f57219082331b66/addons/crm/models/crm_stage.py#L36> __ 和 view <https://github.com/odoo/odoo/blob/892dd6860733c46caf379fd36f57219082331b66/addons/crm/views/crm_stage_views.xml#L23> __。

属性和选项

详细介绍所有可用于微调视图外观的功能将是不切实际的。因此,我们将只介绍最常见的功能。

表单

注解

目标:在本节结束时,属性表单视图将具有:

  • 按钮和字段的条件显示

  • 标签颜色

带有装饰的表单视图

在我们的房地产模块中,我们想要修改一些字段的行为。例如,我们不希望能够从表单视图中创建或编辑属性类型。相反,我们希望在它们适当的菜单中处理这些类型。我们还想给标签添加颜色。为了添加这些行为自定义,我们可以向几个字段小部件添加 options 属性。

Exercise

添加小部件选项。

  • 在属性表单视图中,为 property_type_id 字段添加适当的选项,以防止创建和编辑属性类型。更多信息,请参阅: Many2one widget documentation

  • 添加以下字段:

模型

字段

类型

estate.property.tag

颜色

整数

然后在 tag_ids 字段中添加适当的选项,以在标签上添加颜色选择器。请参阅 FieldMany2ManyTags widget documentation 以获取更多信息。

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

Exercise

添加按钮的条件显示。

使用 states 属性按条件显示标题按钮,如本节的 目标 所示(请注意当状态被修改时,“已售出”和“取消”按钮会发生变化)。

提示:不要犹豫,在Odoo XML文件中搜索 states= 以获取一些示例。

更一般地说,可以通过 attrs 属性根据其他字段的值使字段变为 invisiblereadonlyrequired 。请注意, invisible 也可以应用于视图的其他元素,如 buttongroup

The attrs is a dictionary with the property as a key and a domain as a value. The domain gives the condition in which the property applies. For example:

<form>
    <field name="description" attrs="{'invisible': [('is_partner', '=', False)]}"/>
    <field name="is_partner" invisible="1"/>
</form>

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

Exercise

使用 attrs.

  • 当没有花园时,在 estate.property 表单视图中使花园面积和朝向不可见。

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

  • 不允许在房产状态为’Offer Accepted’、’Sold’或’Canceled’时添加报价。要实现这一点,请使用 readonly attrs

警告

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

列表

注解

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

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

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

Exercise

使列表视图可编辑。

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

另一方面,当一个模型有很多字段时,很容易在列表视图中添加过多的字段,使其变得不清晰。另一种方法是添加这些字段,但是将它们设为可选隐藏。这可以通过 optional 属性来实现。

Exercise

将字段设为可选。

estate.property 列表视图上的字段 date_availability 设置为默认情况下可选和隐藏。

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

<tree decoration-success="is_partner==True">
    <field name="name"/>
    <field name="is_partner" invisible="1"/>
</tree>

is_partnerTrue 时,记录将以绿色显示。

Exercise

添加一些装饰品。

estate.property 列表视图中:

  • 已收到报价的房产标记为绿色

  • 已接受报价的房产为绿色和粗体

  • 已售出的物业已静音

estate.property.offer 列表视图中:

  • 拒绝的报价是红色的

  • 已接受的报价为绿色

  • 该状态不应再可见

小费:

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

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

状态按钮

注解

目标:在本节结束时,属性类型表单视图上将有一个状态按钮,当点击时,它将显示与给定类型的属性相关的所有报价的列表。

统计按钮

如果您已经在Odoo中使用了一些功能模块,您可能已经遇到了“状态按钮”。这些按钮显示在表单视图的右上方,并快速访问链接文档。在我们的房地产模块中,我们希望有一个快速链接到与给定物业类型相关的报价,如本节的 目标 所示。

在本教程的这一点上,我们已经看到了大部分的概念来做到这一点。然而,并没有一个单一的解决方案,如果你不知道从哪里开始,仍然可能会感到困惑。我们将在练习中描述一个逐步解决方案。通过查找 oe_stat_button 在Odoo代码库中的一些示例,这总是有用的。

以下练习可能比之前的练习更难,因为它假设您能够自己在源代码中搜索示例。如果您卡住了,附近可能有人可以帮助您 ;-)

该练习介绍了 相关字段 的概念。最简单的理解方式是将其视为计算字段的特殊情况。下面是 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" 属性(如果需要回顾,请返回到 第十章:准备好行动了吗? 的末尾)。

此时,单击状态按钮应该显示所有报价。我们仍然需要过滤掉这些报价。

  • estate.property.offer 动作上,添加一个域,定义 property_type_id 等于 active_id (= 当前记录, 这里是一个例子 <https://github.com/odoo/odoo/blob/df37ce50e847e3489eb43d1ef6fc1bac6d6af333/addons/event/views/event_views.xml#L162> __)

看起来不错吗?如果不是,别担心, 下一章 不需要状态按钮 ;-)