Skip to content

14. 高级视图

在前面的教程中,创建了特定的视图,添加了多个操作按钮和约束条件,但用户界面目前仍比较粗糙。接下来将在列表视图中增添一些色彩,并让某些字段和按钮在满足特定条件时自动隐藏。例如,当房产已售出或取消时,“已售出”和“取消”操作按钮应自动隐藏,因为此时已不允许更改房产状态。

注: 由于篇幅限制,本章仅介绍了视图功能中的一小部分,如需更全面的概述,请查阅参考Odoo官方文档。

1、内联视图

在本节将学习目标:在房产类型视图中添加一份具体的房产列表,比如:房产类型是“商品楼”下有哪些房产信息?

estate模块中,为某一房产添加了一份报价列表。只是通过以下方式添加了 offer_ids 字段:

xml
<field name="offer_ids"/>

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

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

python
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()

视图代码:

xml
<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 字段。示例请参见此处

开发实现:添加一个内联列表视图

estate.property.type 模型中添加 One2many 字段 property_ids。如本节目标所示,在 estate.property.type 表单视图中添加该字段。

2、Widgets

在本小节学习目标:使用控件显示房产的状态(status),四种状态为:新建收到报价接受报价已售出

当在模型中添加字段时,不必在意这些字段在用户界面中会呈现何种样式。例如,Date 字段会自动提供日期选择器,而 One2many 字段则会自动显示为列表。Odoo 会根据字段类型选择合适的“控件”。

在某些情况下,我们希望以特定方式呈现某个字段,可通过 widget 属性来实现。在前面章节中处理 tag_ids 字段时,曾使用过 widget="many2many_tags" 属性。如果不使用widget属性,字段将以列表形式显示。每种字段类型都有一组可用于精细调整其显示效果的小部件。部分小部件还支持额外选项 - 使用状态栏控件。可使用statusbar控件来显示 estate.property 的状态。

3、列表排序

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

在之前的学习教程中,创建了几个列表视图。但是从未指定过记录默认应按什么顺序排列。对于许多业务场景而言,排序是非常重要的。例如,在estate模块中,更多的是希望将出价最高的报价显示在列表顶部。

3.1、模型

Odoo 提供了多种设置默认排序的方式。最常见的方法是在模型中直接定义 _order 属性。这样检索到的记录将遵循_order 属性指定的规则进行排序,这个排序规则在所有视图中都保持一致,包括通过编程方式搜索记录时。默认情况下未指定排序,因此记录将根据 PostgreSQL 数据库的实现以非确定性顺序检索。

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

python
from odoo import fields, models

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

    description = fields.Char()

记录按 ID 降序排列,即 ID 最小的排在最前面。

开发实现:添加模型排序

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

模型排序备注_order属性值
estate.propertyid descID降序排序_order="id desc"
estate.property.offerprice descprice降序排序_order="id desc"
estate.property.tagnamename升序排序_order="name"
estate.property.typenamename升序排序_order="name"

3.2、视图

可以在模型级别进行排序。这样做的好处是,在检索记录列表时,排序顺序始终保持一致。也可以在视图中定义 default_order 属性指定的排序顺序。类似的示例代码:

python
        <record id="crm_activity_report_view_tree" model="ir.ui.view">
            <field name="name">crm.activity.report.list</field>
            <field name="model">crm.activity.report</field>
            <field name="arch" type="xml">
                <list default_order="date desc">
                    <field name="date"/>
                    <field name="author_id" widget="many2one_avatar"/>
                    <field name="mail_activity_type_id"/>
                    <field name="body" optional="hide"/>
                    <field name="company_id" groups="base.group_multi_company"/>
                    <field name="tag_ids" string="Lead Tags" optional="show" widget="many2many_tags" options="{'color_field': 'color'}"/>
                </list>
            </field>
        </record>

3.3、手动排序

虽然模型和视图排序在对记录进行排序时都提供了灵活性,但还有一种情况需要手动排序。用户可能希望根据业务逻辑对记录进行排序。例如,在estate模块中,希望手动排序房产类型。将使用频率最高的类型置于列表顶部确实很有用。如果房地产中介主要销售独栋住宅,那么将“独栋住宅”排在“公寓”之前会更方便。

为此,需要结合使用序列字段和 handle 控件。显然,序列字段必须是 _order 属性中的第一个字段。

开发实现:添加手动排序

添加以下字段:

模型字段类型
estate.property.typesort_rankInteger

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

提示:可以在此处查看示例:模型视图

python
        <!-- list View -->
        <record id="property_type_list_view" model="ir.ui.view">
            <field name="name">estate.property.type.list</field>
            <field name="model">estate.property.type</field>
            <field name="arch" type="xml">
                <list>
                    <field name="id" string="编号"/>
                    <field name="name" string="类型名称"/>
                    <field name="description" string="描述"/>
                    <field name="sort_rank" string="排序值"  widget="handle"/>
                </list>
            </field>
        </record>

4、属性与选项

Odoo中可用于精细调整视图外观的功能有很多,由于篇幅限制,这里将只介绍其中最常见的几项。

4.1、表单

本小节学习目标:实现属性表单视图,它包含:

  • 按钮和字段的条件显示;

  • 为标签加上颜色;

如下图所示:

estate模块中,用户希望修改某些字段的行为。例如,不希望用户在表单视图中创建或编辑房产类型,这些类型只能在相应的菜单中进行管理。此外,还希望为标签添加颜色。为了实现这些行为自定义,可以为几个字段控件添加 options属性。

xml
        <record id="property_list_view" model="ir.ui.view">
            <field name="name">estate.property.list</field>
            <field name="model">estate.property</field>
            <field name="arch" type="xml">
                <list>
                    <field name="name" string="标题" />
                    <field name="property_type_id" string="类型" />
                    <field name="tag_ids" string="标签" widget="many2many_tags" options="{'color_field': 'color'}" />
                    <field name="description" string="描述" />
                    <field name="postcode" optional="hide" string="邮编" />
                    <field name="date_availability" optional="hide" string="有效期" />
                    <field name="expected_price" string="期望价格" />
                    <field name="selling_price" string="售价" />
                    <field name="bedrooms" optional="hide" string="房间数量" />
                    <field name="living_area" optional="hide" string="室内面积(M²)" />
                    <field name="has_garage" optional="hide" string="有车库" />
                    <field name="has_garden" optional="hide" string="有花园" />
                    <field name="garden_area" optional="hide" string="花园面积(M²)" />
                    <field name="garden_orientation" optional="hide" string="花园朝向" />
                </list>
            </field>
        </record>

开发实现:添加小部件选项

property_type_id 字段中添加相应的选项,以防止在“房产”表单视图中创建和编辑房产类型。如下:

xml
 <field name="property_type_id" options="{'no_create': true, 'no_open': true}"/>

要实现在标签上添加颜色选择器,添加以下字段:

模型字段类型
estate.property.tagcolorInteger

然后在 tag_ids 字段中添加相应的选项,以便在标签上添加颜色选择器。

xml
<field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color'}" />

在《用户界面(UI)》中,有两个预留字段用于实现特定行为:active 字段用于自动过滤掉非活动记录,state 字段可以与视图中的 invisible= 属性结合使用,以实现按条件显示按钮。

xml
<header>
       <button class="oe_highlight" name="action_sold_btn" type="object" string="设置为已售" invisible="state == 'sold'"/>
       <button name="action_cancel_btn" type="object" string="设置为取消" invisible="state in ['sold','canceled']"/>
       <field name="state" widget="statusbar" statusbar_visible="new,received,accepted,sold" />
</header>

可以根据其他字段的值,将某个字段设置为invisiblereadonly 和 requiredinvisible属性也可应用于视图中的其他元素,例如:按钮或组。

invisiblereadonly 和 required的值可以是任何 Python 表达式。表达式指定了该属性适用的条件。例如:

xml
<form>
    <field name="description" string="描述" invisible="not is_partner"/>
</form>

上面示例代码中,当 is_partnerFalse 时,描述字段将不可见。在 invisible 中使用的字段必须存在于视图中。如果不需要向用户显示字段,可以使用 invisible 属性将其隐藏。

开发实现:使用“隐藏”功能

当房产没有花园时,在 estate.property 表单视图中将花园区域和朝向设为隐藏。当报价状态被设定,将 “接受”“拒绝” 按钮设为隐藏。

当房产状态为“报价已接受”、“已售出”或“已取消”时,不允许添加报价。这里可以使用 readonly 属性实现。

在视图中使用(条件)只读属性有助于防止数据输入错误,但这并不能提供任何安全保障!由于服务器端不进行任何检查,因此始终可以通过 RPC 调用对字段进行写入操作。

4.2、列表

本小节学习目标:房源列表视图记录根据状态的不同应带有不同的颜色装饰。房源和标签可在列表中直接编辑,可用日期默认设置为隐藏。

当模型包含较少数量的字段时,直接通过列表视图编辑记录会非常方便,无需打开表单视图。当添加报价或创建新标签时,无需打开表单视图。这是通过 editable 属性来实现的。

开发练习:使列表视图可编辑

使 estate.property.offerestate.property.tag 列表视图可编辑,如下示例代码中,list 标签新增 editable="bottom" 属性。

xml
<record id="property_tag_list_view" model="ir.ui.view">
  <field name="name">estate.property.tag.list</field>
  <field name="model">estate.property.tag</field>
  <field name="arch" type="xml">
    <list editable="bottom">
      <field name="name" string="标签名称"/>
      <field name="description" string="描述"/>
      <field name="sort_rank" string="排序值"/>
    </list>
  </field>
</record>

开发练习:将字段设为可选

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

颜色代码有助于通过视觉效果突出显示记录。例如,将被拒绝的报价显示为红色,而被接受的报价显示为绿色。这可以通过 decoration-{$name} 属性来实现,示例代码如下所示:

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

上面代码中,is_partnerTrue 的记录将以绿色显示。

开发练习:添加装饰

estate.property列表视图中:

  • 收到报价的房产信息显示为绿色;

  • 已接受报价的房产信息显示为绿色且加粗;

  • 已售出的房产信息显示为灰色;

示例代码如下:

xml
<list decoration-success="state == 'sold'" decoration-bf="state == 'sold'" decoration-muted="state == 'canceled'">
    <field name="name...">
    ...
</list>

estate.property.offer列表视图中:

  • 拒绝的报价信息显示为红色;

  • 接受的报价信息显示为绿色;

  • 接收或拒绝报价后,状态操作不再显示;

示例代码如下:

xml
<page string="报价列表">
  <field name="offer_ids" readonly="1">
    <list create="false" edit="false" delete="true" decoration-success="status == 'accepted'" decoration-danger="status == 'refused'">
      <field name="partner_id" string="买家"/>
      <field name="price" string="报价金额(万)"/>
      <field name="status" string="状态"/>
      <button name="action_accepted" string="接受" icon="fa-check" invisible="status in ['accepted','refused']" />
      <button name="action_refused" string="拒绝" icon="fa-close" invisible="status in ['accepted','refused']" />
    </list>                                    
  </field>
</page>

提示:要实现不可编辑功能,需加上:readonly="1", 如上代码所示。

4.3、搜索

本小节的学习目标:系统可默认对可用房源进行筛选,搜索“居住面积”时,系统将返回居住面积大于指定数值的结果。

搜索有时需要进行一些调整。首先,在访问房源时默认应用“可售”筛选条件。可使用search_default_{$name} 代表筛选条件名称,也就是在操作层面上定义哪些筛选条件将默认启用。

添加默认筛选条件

estate.property 操作中,默认选中“居住面积”筛选条件。用户通常希望搜索“至少”达到指定面积的房产。指望用户只想找到居住面积完全符合要求的房产是不现实的。虽然可以随时进行自定义搜索,但这很不方便。

搜索视图中的 <field> 元素可以包含一个 filter_domain 属性,该属性会覆盖针对给定字段生成的搜索域。在搜索域中,self 代表用户输入的值。在下面的示例中,同时搜索 namedescription 字段的值。

xml
<search string="Test">
    <field name="description" string="Name and description"
           filter_domain="['|', ('name', 'ilike', self), ('description', 'ilike', self)]"/>
</search>

更改居住面积的搜索条件

living_area字段中添加一个 filter_domain 筛选条件,以包含面积等于或大于指定值的房源。

示例代码如下:

xml
<search string="搜索条件">
  <field name="name" string="按名称"/>
  <field name="postcode" string="按邮编"/>
  <field name="bedrooms" string="按房间数量"/>
  <field name="expected_price" string="按期望价格"/>
  <field name="selling_price" string="按实际价格"/>
  <field name="living_area" string="按居住面积" filter_domain="[('living_area', '>=', self)]"/>
  <filter name="property_type_id" string="商品楼" domain="[('property_type_id.id', '=', '1')]"/>
  <filter name="villa_type" string="别墅" domain="[('property_type_id.id', '=', '2')]"/>
  <group>
    <filter name="group_by_state" string="按[类型]分组" context="{'group_by': 'property_type_id'}"/>
  </group>
</search>

5、统计按钮

本小节的学习目标:在房产类型表单视图中将出现一个“统计”按钮,点击按钮即可显示与指定类型房产相关的所有报价列表。

可通过房产类型链接,快速的访问此类型相关的房源信息,在 Odoo 代码库中搜索 oe_stat_button 来查找一些示例,通常会很有帮助。

本练习将介绍“相关字段”的概念。理解它的最简单方法是将其视为计算字段的一个特例。以下是对 description 字段的定义:

python
...

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

以上代码等同于:

python
...

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

每次更改合作伙伴名称时,description字段也会随之更新。

开发练习:在“房产类型”中添加一个统计按钮

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

通过此字段,报价在创建时将与房产类型相关联。可以将该字段添加到报价的列表视图中,以确保其正常运行。

  • estate.property.type 表中添加字段 offer_ids,该字段是上一步中定义的字段的“一对多”反向关联。

  • estate.property.type 表中添加字段 offer_count。这是一个计算字段,用于统计给定房产类型的报价数量(使用 offer_ids 实现此功能)。

至此,我们已掌握了判断某类房产关联了多少份报价所需的所有信息。可直接将 offer_idsoffer_count 添加到视图中。下一步是实现点击统计按钮时显示该列表。

  • estate.property.type 上创建一个 stat 按钮,使其指向 estate.property.offer 操作,这里应该使用 type="action" 属性。

此时,点击“统计”按钮应能显示所有报价。我们还需要对这些报价进行筛选。

  • estate.property.offer 操作上,添加一个条件,将 property_type_id 设为等于 active_id(即当前记录,可通过这个示例了解)

示例代码:

xml
<record id="action_estate_property_offer_list" model="ir.actions.act_window">
  <field name="name">PropertyOffer</field>
  <field name="domain">[('property_type_id', '=', active_id)]</field>
  <field name="res_model">estate.property.offer</field>
  <field name="view_mode">list</field>
</record>
最近更新