第 11 章:锦上添花¶
我们的房地产模块现在从业务角度看是合理的。我们创建了 特定的视图,添加了若干 动作按钮 和 约束。然而我们的用户界面仍然有些粗糙。我们想为列表视图添加一些颜色,并让某些字段和按钮按条件消失。例如,当房产已售或已取消时,’Sold’ 和 ‘Cancel’ 按钮应该消失,因为此时已不再允许更改状态。
本章只涵盖视图功能中很小的一部分。不要犹豫,请阅读参考文档以获得更完整的概览。
内联视图¶
注解
目标:本节结束时,房产类型视图中应添加一个特定的房产列表:
在房地产模块中,我们为房产添加了报价列表。我们只是添加了 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表单视图中添加该字段。
部件¶
参考:本节相关文档请参阅 字段。
注解
目标:本节结束时,应使用特定的小部件显示房产的状态:
系统会显示四种状态:新建、收到报价、报价已接受和已售出。
每当我们在模型中添加字段时,(几乎)从不需要操心这些字段在用户界面中会是什么样子。例如,Date 字段会提供一个日期选择器,而 One2many 字段会自动显示为列表。Odoo 会根据字段类型选择合适的“小部件”。
然而,在某些情况下,我们希望字段有特定的显示形式,这可以通过 widget 属性实现。我们之前已经对 tag_ids 字段使用过它,当时使用的是 widget="many2many_tags" 属性。如果没有使用它,那么该字段会显示为列表。
每种字段类型都有一组小部件,可用于精细调整其显示效果。有些小部件还接受额外选项。完整列表请参阅 字段。
警告
同一字段在视图中多次出现
在列表视图或表单视图中,每个字段只能添加 一次。不支持多次添加同一字段。
列表顺序¶
参考:本节相关文档请参阅 型号。
注解
目标:本节结束时,所有列表都应默认按确定性顺序显示。房产类型可以手动排序。
在之前的练习中,我们创建了几个列表视图。然而,我们从未指定记录默认按什么顺序列出。对许多业务场景来说,这一点非常重要。例如,在我们的房地产模块中,我们希望把最高的报价显示在列表顶部。
模型¶
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 降序排列,也就是说最大的排在最前面。
练习
添加模型排序。
在相应的模型中定义以下顺序:
模型 |
顺序 |
|---|---|
|
ID 降序 |
|
价格降序 |
|
名称 |
|
名称 |
视图¶
在模型层面可以进行排序。这样做的好处是,在任何检索记录列表的地方都能获得一致的顺序。不过,也可以直接在视图中通过 default_order 属性指定特定顺序(示例)。
手动¶
模型排序和视图排序都能在排序记录时提供灵活性,但还有一种情况需要涵盖:手动排序。用户可能希望根据业务逻辑对记录排序。例如,在我们的房地产模块中,我们希望手动对房产类型排序。让最常用的类型出现在列表顶部确实很有用。如果我们的房地产中介主要销售房屋,那么把“房屋”排在“公寓”前面会更方便。
为此,需要将 sequence 字段与 handle 小部件配合使用。显然,sequence 字段必须是 _order 属性中的第一个字段。
属性与选项¶
详细介绍所有可精细调整视图外观的可用功能会过于繁琐。因此,我们只介绍最常见的那些。
窗体¶
注解
目标:本节结束时,房产表单视图将具有以下内容:
按钮和字段的条件显示
标签颜色
在我们的房地产模块中,我们想修改一些字段的行为。例如,我们不希望能够从表单视图创建或编辑房产类型,而是期望在对应的菜单中管理这些类型。我们还希望给标签加上颜色。为了添加这些行为定制,我们可以为若干字段小部件添加 options 属性。
练习
添加小部件选项。
为
property_type_id字段添加合适的选项,以阻止从房产表单视图创建和编辑房产类型。更多信息请查看 Many2one 小部件文档。添加以下字段:
模型 |
字段 |
类型 |
|---|---|---|
|
颜色 |
整数 |
然后为 tag_ids 字段添加合适的选项,以便在标签上添加颜色选择器。更多信息请查看 FieldMany2ManyTags 小部件文档。
在 第 5 章:终于有点界面可以玩了 中,我们了解到保留字段用于特定行为。例如,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 列表视图中:
已拒绝的报价显示为红色
已接受的报价显示为绿色
状态字段不应再可见
提示:
请记住,属性中用到的 所有 字段都必须位于视图中!
如果你想测试“收到报价”和“报价已接受”状态的颜色,请在表单视图中添加该字段并手动修改(稍后我们会实现相应的业务逻辑)。
搜索¶
注解
目标:本节结束时,可用的房产将被默认过滤,并且按居住面积搜索时只返回面积大于给定数值的结果。
最后但同样重要的是,在搜索时我们还想做一些调整。首先,我们希望访问房产时默认应用“可用”过滤器。为此,需要使用 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,以包含面积等于或大于给定值的房产。