原文:Odoo 18 官方开发教程“Server framework 101”第 11 章。本文尽量保留原文结构、代码、练习与图片,仅进行中文翻译,并在文末增加“老赵解读”。
第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_1 和 field_2。
可以找到一个例子
这里。
练习
添加内联列表视图。
- 将
One2many字段property_ids添加到estate.property.type模型。- 在
estate.property.type表单视图中添加字段,如以下所示 目标 这个的
部分。
小部件
参考:与本节相关的文档可以在
字段。
说明
目标:在本节末尾,应使用 a 显示房产的状态
具体小部件:
显示四种状态:新、报价已收到、报价已接受并已售出。
每当我们将字段添加到模型时,我们(几乎)从来不必担心如何
这些字段在用户界面中看起来像这样。例如,提供了日期选择器
对于 Date字段和 One2many字段会自动显示为列表。奥杜
根据字段类型选择正确的“小部件”。
然而,在某些情况下,我们需要字段的特定表示,这可以通过以下方式完成
widget 属性。当我们使用
widget="many2many_tags" 属性。如果我们没有使用它,那么字段将显示为
列表。
每个字段类型都有一组小部件,可用于微调其显示。一些小部件也
采取额外的选择。详细列表可在 字段 中找到。
练习
使用状态栏小部件。
使用
statusbar小部件将estate.property的state显示为
中描绘的 目标 本节的。提示:可以找到一个简单的例子
这里。警告
在一个视图中多次出现相同的字段
仅添加字段 一次 到列表或表单视图。多次添加就是
不支持。
列表顺序
参考:与本节相关的文档可以在
模型。
说明
目标:在本节末尾,所有列表都应默认以确定性方式显示
订单。房产类型可以手动订购。
在前面的练习中,我们创建了几个列表视图。然而,我们从未指定
默认情况下记录必须按哪个顺序列出。这对于很多企业来说是非常重要的事情
案例。例如,在我们的房地产模块中,我们希望在顶部显示最高的报价
列表。
模型
Odoo 提供了多种设置默认顺序的方法。最常见的方法是定义
_order 属性直接位于模型中。这样,检索到的记录将跟随
确定性顺序在所有视图中都保持一致,包括搜索记录时
以编程方式。默认情况下没有指定顺序,因此记录将是
根据 PostgreSQL 以不确定的顺序检索。
_order 属性采用一个包含字段列表的字符串,该列表将用于排序。
它将转换为 SQL 中的 订单依据 子句。例如:
from odoo import fields, models
class TestModel(models.Model):
_name = "test_model"
_description = "Test Model"
_order = "id desc"
description = fields.Char()
我们的记录按 id 降序排列,这意味着最高的排在前面。
练习
添加模型订购。
在其对应的模型中定义以下命令:
模型 订单 estate.property降序 ID estate.property.offer降价价格 estate.property.tag名称 estate.property.type名称
查看
可以在模型级别订购。这样做的优点是各处的顺序一致
检索记录列表。然而,也可以直接定义特定的顺序
由于 default_order 属性,在视图中
(例子)。
手册
模型和视图排序都在排序记录时提供了灵活性,但仍然存在一种情况
我们需要涵盖: 手动订购。用户可能希望根据业务对记录进行排序
逻辑。例如,在我们的房地产模块中,我们希望手动对房产类型进行排序。
将最常用的类型显示在列表顶部确实很有用。如果我们的房地产
Agency主要销售房屋,“House”出现在“Apartment”之前更方便。
为此,需要将 sequence字段与 handle 小部件结合使用。显然
sequence字段必须是 _order 属性中的第一个字段。
练习
添加手动订购。
- 添加以下字段:
模型 字段 类型 estate.property.type序列 Integer
- 使用正确的小部件将序列添加到
estate.property.type列表视图中。
属性和选项
详细说明允许微调外观的所有可用功能是令人望而却步的。
视图。因此,我们将坚持使用最常见的。
形式
说明
目标:在本节末尾,房产表单视图将具有:
- 按钮和字段的条件显示
- 标签颜色
在我们的房地产模块中,我们想要修改一些字段的行为。例如,我们不
希望能够从表单视图创建或编辑房产类型。相反,我们期望
在适当的菜单中处理的类型。我们还想给标签指定颜色。为了添加这些
行为自定义,我们可以将 options 属性添加到多个字段小部件。
练习
添加小部件选项。
- 将适当的选项添加到
property_type_id字段以防止创建和
从房产表单视图编辑房产类型。看看
Many2one 小部件文档 了解更多信息。- 添加以下字段:
模型 字段 类型 estate.property.tag颜色 Integer 然后将适当的选项添加到
tag_ids字段以在标签上添加颜色选择器。
看看 FieldMany2ManyTags 小部件文档
了解更多信息。
在第 5 章:最后,一些可以使用的 UI中,我们看到保留的字段用于
具体行为。例如 active字段用于自动过滤掉
不活动记录。我们还添加了 state 作为保留的字段。现在是时候使用它了!
state字段可以与视图中的 invisible 属性结合使用来显示
有条件地按钮。
练习
添加按钮的条件显示。
使用
invisible属性有条件地显示标题按钮,如图所示
在本节的 目标 (请注意状态更改时“已售出”和“取消”按钮如何变化)。提示:请随时在 Odoo XML 文件中搜索
invisible=以获取一些示例。
更一般地,可以制作基于字段 invisible、readonly 或 required 的
关于其他字段的价值。请注意,invisible 也可以应用于其他元素
诸如 button 或 group 之类的视图。
invisible、readonly 和 required 可以使用任何 Python 表达式作为值。表达式
给出房产适用的条件.例如:
<form>
<field name="description" invisible="not is_partner"/>
</form>
这意味着当 is_partner 为 False 时,description字段不可见。
练习
使用
invisible。
- 使花园面积和方向在
estate.property表单视图中不可见
没有花园。- 设置报价状态后,使“接受”和“拒绝”按钮不可见。
- 当房产状态为“报价已接受”、“已售出”或
‘取消’。为此,请使用readonly属性。警告
在视图中使用(有条件的)
readonly属性有助于防止数据输入
错误,但请记住,它不提供任何级别的安全性!没有检查完成
服务器端,因此始终可以通过 RPC 调用在字段上写入。
列表
说明
目标:在本节末尾,房产和报价列表视图应该有颜色装饰。
此外,报价和标签可直接在列表中编辑,可用日期为
默认隐藏。
当模型只有几个字段时,直接通过列表编辑记录会很有用
视图而不必打开表单视图。在房地产示例中,无需打开表单视图
添加报价或创建新标签。这可以通过 editable 属性来实现。
练习
使列表视图可编辑。
使
estate.property.offer和estate.property.tag列表视图可编辑。
另一方面,当模型有很多字段时,可能会很容易在字段中添加太多字段
列表视图并使其不清楚。另一种方法是添加字段,但使它们可选
隐藏的。这可以通过 optional 属性来实现。
练习
将字段设为可选。
使
estate.property列表视图上的字段date_availability成为可选并隐藏
默认。
最后,颜色代码有助于在视觉上强调记录。例如,在房地产领域
我们希望将拒绝的报价显示为红色,接受的报价显示为绿色。这是可以实现的
感谢 decoration-{$name} 属性(请参阅 字段 了解更多信息)
完整列表):
<list decoration-success="is_partner==True">
<field name="name"/>
</list>
其中 is_partner 为 True 的记录将显示为绿色。
练习
添加一些装饰。
在
estate.property列表视图上:
- 收到报价的房产为绿色
- 房产接受的报价为绿色且粗体
- 房产出售时静音
在
estate.property.offer列表视图上:
- 拒绝的报价是红色
- 已接受的报价为绿色
- 状态不应该再可见
温馨提示:
- 请记住 全部 字段中使用的属性必须在视图中!
- 如果要测试“报价Received”和“报价Accepted”状态的颜色,请添加
字段在表单视图中手动更改它(我们稍后将实现此业务逻辑)。
搜索
说明
目标:在本节末尾,将默认过滤可用的房产,
并且搜索居住区域会返回面积大于给定值的结果
数量。
最后但并非最不重要的一点是,我们希望在搜索时应用一些调整。首先,我们
希望在访问房产时默认应用“可用”过滤器。为了实现这一目标,我们
需要使用 search_default_{$name} 操作上下文,其中 {$name} 是过滤器名称。
这意味着我们可以定义在操作级别默认激活哪些过滤器。
练习
添加默认过滤器。
在
estate.property操作中默认选择“可用”过滤器。
我们模块的另一个有用的改进是能够按居住区域进行有效搜索。
在实践中,用户将希望搜索“至少”给定区域的房产。这是不现实的
期望用户想要找到一个精确的居住区域的房产。总是
可以进行自定义搜索,但这很不方便。
搜索视图 <field> 元素可以具有覆盖的 filter_domain
为在给定的字段上进行搜索而生成的域。在给定的域中,
self 表示用户输入的值。在下面的例子中,它是
用于搜索 name 和 description字段。
<search string="Test">
<field name="description" string="Name and description"
filter_domain="['|', ('name', 'ilike', self), ('description', 'ilike', self)]"/>
</search>
练习
更改居住区搜索。
将
filter_domain添加到生活区域,以包括面积等于或的房产
大于给定值。
统计按钮
说明
目标:在本节末尾,房产类型表单视图上将有一个统计按钮
单击时,它会显示与给定类型的房产相关的所有报价的列表。
如果您已经使用过 Odoo 中的一些功能模块,您可能已经遇到过“stat
按钮”。这些按钮显示在表单视图的右上角,可以快速访问
链接的文档。在我们的房地产模块中,我们希望有一个到报价的快速链接
与给定的房产类型相关,如 目标 本节的。
在本教程的这一点上,我们已经了解了执行此操作的大部分概念。然而,
没有单一的解决方案,如果您不知道从哪里开始,它仍然会令人困惑。
我们将在练习中描述逐步解决方案。找到一些总是有用的
通过查找 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
每次更改合作伙伴名称时,都会修改描述。
练习
将统计按钮添加到房产类型。
- 将字段
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_ids和offer_count直接添加到视图中。
下一步是在单击统计按钮时显示列表。
- 在
estate.property.type上创建一个指向estate.property.offer的统计按钮
行动。这意味着您应该使用type="action"属性(返回到末尾)
第 9 章:准备好采取行动了吗?(如果您需要复习)。此时,单击统计按钮应显示所有报价。我们仍然需要过滤掉
报价。
- 在
estate.property.offer操作上,添加定义property_type_id的域
等于active_id(= 当前的记录,
这是一个例子)
看起来不错吗?如果没有,别担心,下一章 不需要统计按钮;-)
老赵解读
这一章加入的内联视图、状态栏、装饰、默认筛选和统计按钮,看起来是界面“点缀”,其实都在降低用户理解流程和定位信息的成本。
交互优化要围绕业务优先级,而不是追求控件数量。颜色只用于传递明确状态,默认筛选必须符合多数人的工作范围,统计按钮应连接用户下一步最常执行的动作。