Alan Hou的个人博客

Odoo 17开发者指南第九章 后端视图

在所有前面的章节中,您已经了解了 Odoo 的服务器和数据库端。在本章中,我们将看到 Odoo 的用户界面端。您将学习如何创建不同类型的视图。除了视图之外,本章还涵盖了其他组件,例如动作按钮、菜单和微件,这将帮助您使应用程序更加用户友好。完成本章后,您将能够设计 Odoo 后端的 UI。请注意,本章不涵盖 Odoo 的网站部分;我们为此单独设置了一章(第 14 章)。

在本章中,我们将涵盖以下小节:

技术要求

在整章中,我们将假设您有一个已安装基础(base)附加模块的数据库,以及一个空的 Odoo 附加模块,您可以将小节中的 XML 代码添加到该附加模块清单文件(manifest)中引用的数据文件中。有关如何激活附加模块更改的更多信息,请参阅第 3 章《创建 Odoo 附加模块》。

本章的技术要求包括一个在线 Odoo 平台。

本章中使用的所有代码都可以从 GitHub 仓库下载:https://github.com/PacktPublishing/Odoo-17-Development-Cookbook-Fifth-Edition/tree/main/Chapter09

添加菜单项和窗口动作

使新功能对用户可用的最明显方式是添加菜单项。当您点击菜单项时,会发生一些事情。本小节将引导您完成如何定义“那些事情”。

我们将创建一个顶级菜单及其子菜单,该子菜单将打开所有旅馆房间的列表。

这也可以通过设置菜单下的 Web 用户界面来完成,但我们更喜欢使用 XML 数据文件,因为这是我们在创建附加模块时必须使用的。

准备工作

在本小节中,我们将需要一个依赖于 base 模块的模块,因为 my_hostel 模块会向 hostel.room 模型添加新字段。因此,如果您使用的是现有模块,请在清单文件中添加 base 依赖项。另外,您可以从 https://github.com/PacktPublishing/Odoo-17-Development-Cookbook-Fifth-Edition/tree/main/Chapter09/00_initial_module 获取初始模块。

如何实现…

在我们附加模块的 XML 数据文件中,执行以下步骤:

  1. 定义要执行的动作:
  2. >创建顶级菜单,如下所示:
  3. 在菜单中引用我们的动作:

现在,如果我们升级模块,我们将看到一个标签为 Hostel Room 的顶级菜单,它会打开一个名为 All Hostel Room 的子菜单。点击该菜单项将打开所有旅馆房间的列表。

工作原理…

第一个 XML 元素 <record model="ir.actions.act_window"> 声明了一个窗口动作(window action),用于显示所有旅馆房间的列表视图。我们使用了最重要的属性:

接下来,我们创建菜单项层次结构,从顶级菜单到可点击的末端菜单项。menuitem 元素最重要的属性如下:

窗口动作通过查找目标模型中具有预期类型(formtree 等)的视图并选择序列号最低的那个来自动确定要使用的视图。ir.actions.act_windowmenuitem 是方便的快捷 XML 标签,它们隐藏了您实际正在做的事情。如果您不想使用快捷 XML 标签,则可以通过 <record> 标签创建 ir.actions.act_windowir.ui.menu 模型的一条记录。例如,如果您想使用 <record> 加载 act_window,可以按如下方式操作:

以同样的方式,您可以通过 <record> 创建 menuitem 实例。

重要提示

请注意,与 menuitem 快捷方式一起使用的名称可能不会映射到使用 record 元素时使用的字段名称;parent 应该是 parent_idgroups 应该是 groups_id

为了构建菜单,Web 客户端从 ir.ui.menu 读取所有记录,并从 parent_id 字段推断出它们的层次结构。菜单也会根据用户对模型和分配给菜单和动作的组的权限进行筛选。当用户点击菜单项时,其动作就会执行。

更多内容…

窗口动作还支持一个 target 属性来指定视图的呈现方式。可能的选择如下:

窗口动作还有一些额外的属性,ir.actions.act_window 快捷标签不支持这些属性。要使用它们,我们必须使用具有以下字段的 record 元素:

请记住,左上角的菜单(或企业版中的应用图标)和顶部栏中的菜单都由菜单项组成。唯一的区别是左上角菜单中的项没有任何父菜单,而顶部栏上的项将其各自的菜单项作为父级。在左侧栏中,层次结构更为明显。

此外,请记住,出于设计原因,如果您的二级菜单有子菜单,则一级菜单将打开下拉菜单。在任何情况下,Odoo 都会根据子菜单项的序列打开第一个菜单项的动作。

请参阅以下内容以了解有关菜单和视图的更多信息:

让动作打开特定的视图

如果没有给出视图,窗口动作会自动确定要使用的视图,但有时,我们希望动作打开特定的视图。

我们将为 hostel.room 模型创建一个基本表单视图,然后我们将创建一个新的窗口动作来专门打开该表单视图。

如何实现…

  1. 定义旅馆房间最小列表视图和表单视图:
  2. 更新《添加菜单项和窗口动作》小节中的动作以使用新的表单视图:

现在,如果您打开菜单并点击列表中的一个伙伴,您应该会看到我们刚刚定义的极简表单和列表。

工作原理…

这次,我们使用了适用于任何类型记录的通用 XML 代码,即带有必需的 idmodel 属性的 record 元素。record 元素上的 id 属性是一个任意字符串,对于您的附加模块来说必须是唯一的。model 属性引用您要创建的模型的名称。鉴于我们要创建一个视图,我们需要创建 ir.ui.view 模型的一条记录。在此元素中,您设置通过 model 属性选择的模型中定义的字段。对于 ir.ui.view,关键字段是 modelarchmodel 字段包含要为其定义视图的模型,而 arch 字段包含视图本身的定义。我们稍后会介绍它的内容。

name 字段虽然不是严格必需的,但在调试视图问题时很有帮助。因此,将其设置为一个字符串,告诉您此视图的预期用途。此字段的内容不会向用户显示,因此您可以填写您认为合理的任何技术提示。如果您在此处未设置任何内容,您将获得一个包含模型名称和视图类型的默认名称。

ir.actions.act_window.view

我们定义的第二条记录与我们在《添加菜单项和窗口动作》小节中定义的 act_window 协同工作。我们已经知道,通过在那里设置 view_id 字段,我们可以选择用于第一个视图模式的视图。然而,鉴于我们将 view_mode 字段设置为 tree,form 视图,view_id 将不得不选择一个列表视图,但我们想设置表单视图,它在这里排在第二位。

如果您发现自己处于这种情况,请使用 ir.actions.act_window.view 模型,它为您提供了对为哪种视图类型加载哪个视图的细粒度控制。此处定义的前两个字段是引用其他对象的通用方式的示例;您将元素的正文留空,但添加一个名为 ref 的属性,其中包含您要引用的对象的 XML ID。因此,这里发生的事情是我们在 act_window_id 字段中引用了我们上一个小节中的动作,并在 view_id 字段中引用了我们刚刚创建的视图。然后,虽然不是严格必需的,但我们添加了一个序列号来定位此视图分配相对于同一动作的其他视图分配的位置。这仅在您通过创建多个 ir.actions.act_window.view 记录来为不同的视图模式分配视图时才相关。

重要提示

一旦您定义了 ir.actions.act_window.view 记录,它们将优先于您在动作的 view_mode 字段中填写的内容。因此,使用前面的记录,您根本看不到列表,而只能看到表单。您应该添加另一条 ir.actions.act_window.view 记录,指向 hostel.room 模型的列表视图。

更多内容…

正如我们在《添加菜单项和窗口动作》小节中看到的那样,我们可以用 <record> 替换 act_window。如果您想使用自定义视图,可以遵循给定的语法:

此示例只是 act_window 的替代方案。在 Odoo 的代码库中,您会发现这两种类型的动作。

向表单视图添加内容和微件

前面的小节展示了如何为动作选择特定的视图。现在,我们将演示如何使表单视图更有用。在本小节中,我们将使用我们在《让动作打开特定的视图》小节中定义的表单视图。在表单视图中,我们将添加微件和内容。

如何实现…

  1. 定义表单视图的基本结构:

  2. 要添加通常用于动作按钮和阶段管道的头部栏,请在 form 内部添加此内容:

  3. 向表单添加字段,使用 group 标签在视觉上组织它们:

现在,表单应该显示一个带有按钮和两个垂直对齐字段的顶部栏,如下图所示:

图 9.1 – 表单视图的屏幕截图

工作原理…

我们首先来看 ir.ui.view 模型的 arch 字段。首先,请注意视图是在 XML 中定义的,因此您需要为 arch 字段传递 type="xml" 属性;否则,解析器会感到困惑。您的视图定义包含格式正确的 XML 也是强制性的;否则,当您升级/安装模块时,您将收到类似 Element odoo has extra content 的错误。

现在我们将遍历我们以前使用过的标签,并总结其他可用的标签。

form

当您定义表单视图时,arch 字段中的第一个元素必须是 form 元素。这在内部用于派生记录的类型字段。

除了以下元素之外,您可以在 form 标签内使用任意 HTML。该算法规定,Odoo 未知的每个元素都被视为纯 HTML,并简单地传递给浏览器。请注意这一点,因为您填写的 HTML 可能会与 Odoo 元素生成的 HTML 代码交互,这可能会扭曲渲染。

header

此元素是应在表单头部显示的元素的容器,该头部渲染为白色条。通常,如本例所示,您将动作按钮放在此处。或者,如果您的模型具有状态字段,您可以选择状态栏。

button

button 元素用于允许用户触发动作。有关详细信息,请参阅《向表单添加按钮》小节。

<group>

<group> 元素是 Odoo 的主要元素,用于组织内容。放置在 <group> 元素内的字段会以其标题进行渲染,并且同一组内的所有字段都会对齐,因此也有一个视觉指示器表明它们属于一起。您也可以嵌套 <group> 元素;这会导致 Odoo 将包含的字段渲染在相邻的列中。

通常,您应该使用 <group> 机制在表单视图中显示所有字段,并且只在必要时才返回到其他元素,例如 <notebook><label><newline> 等。

如果您将 string 属性分配给组,其内容将渲染为组的标题。

您还应该养成给每组逻辑字段分配一个 name 的习惯。此名称对用户不可见,但在我们在以下小节中覆盖视图时非常有用。保持名称在表单定义中是唯一的,以避免对您引用的哪个组感到困惑。不要为此使用 string 属性,因为 string 的值最终会因翻译而改变。

field

为了实际显示和操作数据,您的表单视图应该包含一些 field 元素。这是一个示例:

这些元素有一个必需的属性,名为 name,它引用模型中的字段名称。之前,我们为用户提供了编辑伙伴类别的能力。如果只想禁用字段上的编辑功能,我们可以将 readonly 属性设置为 1True。此属性实际上可能包含 Python 代码的一个小子集,因此 readonly="2>1" 也会使该字段只读。这也适用于 invisible 属性,您曾经使用它来获取从数据库中读取但未向用户显示的值。稍后,我们将看看可以在哪些情况下使用它。

您一定注意到了类别字段中的 widget 属性。这定义了数据应该如何呈现给用户。每种类型的字段都有一个标准微件,因此您不必显式选择微件。但是,有几种类型提供了多种表示方式,因此您可能会选择非默认值。由于可用微件的完整列表会超出本小节的范围,因此请查阅 Odoo 的源代码以试用它们。查看第 14 章《CMS 网站开发》了解如何制作您自己的微件。

<notebook><page>

如果您的模型有太多字段,则可以使用 <notebook><page> 标签来创建选项卡。<notebook> 标签中的每个 <page> 都将创建一个新选项卡,页面内的内容将是选项卡内容。以下示例将创建两个选项卡,每个选项卡中有三个字段:

<page> 标签中的 string 属性将是选项卡的名称。您只能在 <notebook> 标签中使用 <page> 标签,但在 <page> 标签中,您可以使用任何其他元素。

通用属性

在大多数元素(这包括 groupfieldbutton)上,您可以设置 attributesgroups 属性。这是一个小例子:

虽然 attributes 在《使用属性的动态表单元素》小节中讨论,但 groups 属性为您提供了仅向某些组的成员显示某些元素的可能性。简单地说,组的完整 XML ID(对于多个组,用逗号分隔)是属性,对于不是所提及的组中至少一个成员的每个人,该元素都将被隐藏。

其他标签

在某些情况下,您可能希望偏离严格的布局组规定。例如,如果您希望记录的 name 字段渲染为标题,则字段的标签会干扰外观。在这种情况下,不要将您的字段放入 group 元素中,而是将其放入纯 HTML h1 元素中。然后,在 h1 元素之前,放置一个 label 元素,其 for 属性设置为您的字段名称:

这将以字段的内容作为大标题进行渲染,但字段的名称将以较小的字体写在大标题上方。这基本上就是标准伙伴表单所做的。

如果您需要在组内换行,请使用 newline 元素。它总是空的:

另一个有用的元素是 footer。当您以弹出窗口形式打开表单时,这是一个放置动作按钮的好地方。它也将渲染为一个单独的栏,类似于 header 元素。

表单视图还有特殊的微件,例如 web_ribbon。您可以按如下方式与 <widget> 标签一起使用它:

您可以使用属性根据条件隐藏和显示功能区。如果您不了解属性,请不要担心。它将在本章的《使用属性的动态表单元素》小节中介绍。

重要提示

不要使用 XML 节点的 string 属性(或任何其他已翻译的属性)来寻址 XML 节点,因为您的视图覆盖会因其他语言而损坏,因为视图是在应用继承之前翻译的。

更多内容…

由于表单视图基本上是带有一些扩展的 HTML,Odoo 也广泛使用了 CSS 类。两个非常有用的类是 oe_read_onlyoe_edit_only。具有这些类的元素将分别仅在只读模式或编辑模式下可见。例如,要使标签仅在编辑模式下可见,请使用以下内容:

另一个非常有用的类是 oe_inline,您可以在字段上使用它,使其渲染为内联元素,以避免引起不必要的换行。当您将字段嵌入到文本或其他标记标签中时,请使用此类。

此外,form 元素可以具有 createeditdelete 属性。如果您将其中一个设置为 false,则此表单将不可用相应的动作。如果未明确设置此项,则动作的可用性是从用户的权限推断出来的。请注意,这纯粹是为了整理 UI;不要将此用于安全性。

参见

向表单添加按钮

按钮用于表单视图中以处理用户动作。我们在上一个小节的表单视图中添加了一个按钮,但我们可以使用相当多的不同类型的按钮。本小节将添加另一个按钮,它将帮助用户打开另一个视图。它还将把以下代码放在小节的 header 元素中。

如何实现…

添加一个引用动作的按钮:

工作原理…

按钮的 type 属性决定了其他字段的语义,因此我们首先来看看可能的值:

更多内容…

使用 btn-primary CSS 类来渲染突出显示的按钮,使用 btn-default 来渲染普通按钮。这通常用于向导中的取消按钮或以视觉上不引人注目的方式提供辅助动作。设置 oe_link 类会导致按钮看起来像一个链接。您还可以使用其他 Bootstrap 按钮类来获得不同的按钮颜色。

使用 object 类型的按钮的调用可以返回描述动作的字典,然后将在客户端执行该动作。通过这种方式,您可以实现多屏幕向导或只打开另一条记录。

重要提示

请注意,点击按钮总是会导致客户端在运行方法之前发出 writecreate 调用。

您还可以通过替换 string 属性在 button 标签内添加内容。这通常用于按钮框中,如《文档风格的表单》小节中所述。

向表单和动作传递参数 – 上下文

在内部,Odoo 中的每个方法都可以访问一个名为 context 的字典,该字典从每个动作传播到参与提供该动作的方法。UI 也可以访问它,并且可以通过在上下文中设置值以各种方式对其进行修改。在本小节中,我们将通过使用语言、默认值和隐式筛选器来探索此机制的一些应用。

准备工作

虽然不是严格必需的,但如果您尚未安装法语,本小节会更有趣。有关如何执行此操作,请参阅第 11 章《国际化》。如果您有一个法语数据库,请将 fr_FR 更改为其他语言,例如 en_US 适用于英语。此外,点击其中一个旅馆房间的激活按钮(当您将鼠标悬停在其上时会更改为归档)以将其归档,并验证此伙伴不再显示在列表中。

如何实现…

  1. 创建一个新动作,与《添加菜单项和窗口动作》小节中的动作非常相似:

  1. 添加调用此动作的菜单。这留给读者作为练习。

当您打开此菜单时,视图将以法语显示,如果您创建新伙伴,它们将以法语作为预选语言。一个不太明显的区别是您还将看到停用(已归档)的伙伴记录。

工作原理…

上下文字典是从几个来源填充的。首先,读取当前用户的记录中的一些值(langtz 分别用于用户的语言和用户的时区)。然后,我们有一些附加模块添加用于自己目的的键。此外,UI 添加了有关我们当前正在使用的模型和记录的键(active_idactive_idsactive_model)。此外,如《让动作打开特定的视图》小节中所述,我们可以在动作中添加我们自己的键。这些键合并在一起并传递给底层服务器函数和客户端 UI。

因此,通过设置 lang 上下文键,我们强制显示语言为法语。您会注意到这不会更改整个 UI 语言;这是因为只有我们打开的列表视图在此上下文的范围内。其余的 UI 已经加载了另一个包含用户原始语言的上下文。但是,如果您在此列表视图中打开一条记录,它也将以法语显示,并且如果您在表单上打开链接记录或按下执行动作的按钮,语言也将被传播。

通过设置 default_lang,我们为在此上下文范围内创建的每条记录设置了一个默认值。一般模式是 default_$fieldname: my_default_value,它使您能够在这种情况下为新创建的伙伴设置默认值。鉴于我们的菜单是关于旅馆房间的,我们默认添加了 default_room_rating: 1 作为旅馆平均评分字段的值。但是,这是 hostel.room 的模型范围默认值,因此这不会改变任何内容。对于标量字段,其语法与您在 Python 代码中编写的语法相同:字符串字段用引号括起来,数字字段保持原样,布尔字段要么是 True,要么是 False。对于关系字段,语法稍微复杂一些;请参阅第 6 章《管理模块数据》了解如何编写它们。

重要提示

请注意,在上下文中设置的默认值会覆盖在模型定义中设置的默认值,因此您可以在不同的情况下拥有不同的默认值。

最后一个键是 active_test,它具有非常特殊的语义。对于每个具有名为 active 的字段的模型,Odoo 会自动筛选出此字段为 False 的记录。这就是您取消选中此字段的伙伴从列表中消失的原因。通过设置此键,我们可以抑制此行为。

重要提示

这对于 UI 本身很有用,但在您的 Python 代码中更有用,当您需要确保操作应用于所有记录,而不仅仅是活动的记录时。

更多内容…

在定义上下文时,您可以访问一些变量,其中最重要的是 uid,它评估当前用户的 ID。您需要它来设置默认筛选器(请参阅下一个小节《定义记录列表上的筛选器 – 域》)。此外,您可以访问 context_today 函数和 current_date 变量,其中第一个是表示当前日期的日期对象,从用户的时区看,后者是当前日期,从 UTC 看,格式为 YYYY-MM-DD。要将日期字段的默认值设置为当前日期,请使用 current_date,对于默认筛选器,请使用 context_today()

此外,您可以使用 Python 的 datetimetimerelativedelta 类的一个子集进行一些日期计算。

重要提示

大多数域是在客户端评估的。出于安全原因,服务器端域评估受到限制。当引入客户端评估时,为了不破坏整个系统,最好的选择是在 JavaScript 中实现 Python 的一部分。Odoo 中内置了一个小型 JavaScript Python 解释器,它适用于简单的表达式,通常就足够了。

请注意在 <record id="action_name" model="ir.actions.act_window.view"> 快捷方式中使用 context 变量。这些是在安装时评估的,这几乎不是您想要的。如果您在上下文中需要变量,请使用 <record /> 语法。

我们还可以为按钮添加不同的上下文。它的工作方式与我们向动作添加上下文键的方式相同。这会导致按钮调用的函数或动作在给定的上下文中运行。

大多数评估为 Python 的表单元素属性也可以访问上下文字典。invisiblereadonly 属性就是这些示例。因此,在您希望元素有时出现在表单中但有时不出现的情况下,请将 invisible 属性设置为 context.get('my_key')。对于导致该字段应该不可见的动作,将上下文键设置为 my_key: True。此策略使您能够适应表单,而无需为不同场合重写它。

您还可以为关系字段设置上下文,这会影响字段的加载方式。通过将 form_view_reftree_view_ref 键设置为视图的完整 XML ID,您可以为此字段选择特定的视图。当您为同一对象拥有多个相同类型的视图时,这是必需的。没有此键,您将获得序列号最低的视图,这可能并不总是可取的。

参见

定义记录列表上的筛选器 – 域

我们已经在本章的第一个小节中看到了一个域的示例,即 [('state', '=', 'draft')]。通常,您需要从动作中显示所有可用记录的子集,或者只允许可能的记录子集成为多对一关系的目标。在 Odoo 中描述这些筛选器的方式是使用(domains)。本小节说明了如何使用域来显示精选的伙伴。

如何实现…

要从您的动作中显示伙伴的子集,您需要执行以下步骤:

  1. 创建一个“state”设置为“draft”时的动作:

  2. 添加调用这些动作的菜单。这留给读者作为练习。

工作原理…

域的最简单形式是一个包含三个元组的列表,其中第一个元素是字段名称(该模型的)作为字符串,第二个元素是运算符作为字符串,第三个元素是字段要检查的值。这就是我们之前所做的,这被解释为:“所有这些条件都必须适用于我们感兴趣的记录。”这实际上是一个快捷方式,因为域知道两个前缀运算符——&|——其中 & 是默认值。因此,以规范化形式,第一个域将写成如下:

虽然这些对于更大的表达式可能有点难以阅读,但前缀运算符的优势在于它们的范围被严格定义,这使您无需担心运算符优先级和括号。它总是两个表达式:第一个 & 适用于 &('state', '=', 'draft'),其中 ('room_rating', '&gt;', '0.0') 是第一个操作数,('room_rating', '&gt;', '0.0') 是第二个操作数。然后,我们有第一个操作数,('room_rating', '&gt;', '0.0') 是第二个操作数。

在第二步中,我们必须写出完整的形式,因为我们需要 | 运算符。

例如,假设我们有一个复杂的域,如下所示:['|', ('user_id', '=', uid), '&', ('lang', '!=', 'fr_FR'), '|', ('phone', '=', False), ('email', '=', False)]。请参阅下图了解如何运算此域:

图 9.2 – 域的运算

还有一个用于否定的 ! 运算符,但考虑到逻辑等价和否定的比较运算符(例如 !=not in),它并不是真正必需的。

重要提示

请注意,这是一个一元前缀运算符,因此它仅适用于域中的下一个表达式,而不适用于后续的所有内容。

请注意,当您为窗口动作或其他客户端域编写域时,右操作数不需要是固定值。您可以使用与《向表单和动作传递参数 – 上下文》小节中描述的相同的最小 Python,因此您可以编写诸如“上周更改”或“我的伙伴”之类的筛选器。

更多内容…

前面的域仅适用于模型本身的字段,而我们通常需要根据链接记录的属性进行筛选。为此,您可以使用在 @api.depends 定义或相关字段中也使用的表示法:从当前模型到要筛选的模型创建点路径。要搜索具有属于以字母 G 开头的组的销售人员的伙伴,您将使用 [('user_id.groups_id.name', '=like', 'G%')] 域。路径可以很长,因此您只需确保当前模型和要筛选的模型之间存在关系字段即可。

运算符

下表列出了可用的运算符及其语义:

运算符(等价符号)语法
=, !=, <>第一个为精准匹配,第二为不等于,最一个是已淘汰的不等于标记。
in, not in这会检查值是否在右侧运算项列表中。以 Python 列表的形式给出:[('uid', 'in', [1, 2, 3])]或[('uid', 'not in', [1, 2, 3])]。
<, <=小于,小于等于
>, >=大于,大于等于
like, not like 检查右侧运算项是否包含在值中(子字符串)。
ilike, not ilike与上面一个相同,但忽略大小写。
=like, =ilike可以在这里搜索模式:%匹配任意字符串,_匹配单个字符。这与 PostgreSQL中的 like 等价。
child_of对带有 parent_id 字段的模型,它搜索右侧运算项的子项。右侧运算项包含于结果中。
=?如果右侧运算项为 false 运行结果为 true;否则它和=相同。这用于由程序生成的域,在设置值时用值进行过滤,否则忽略该值。

表 9.1 – 运算符及其语义

请注意,某些运算符仅适用于某些字段和值。例如,域 [('category_id', 'in', 1)] 无效,并且会生成错误,而域 [('category_id', 'in', [1])] 有效。

使用域搜索的陷阱

这一切对于传统字段都工作正常,但一个臭名昭著的问题是搜索未存储的函数字段的值。人们通常会省略搜索函数。这很容易通过在您自己的代码中提供搜索函数来解决,如第 4 章《应用模型》中所述。

另一个可能让开发人员感到困惑的问题是 Odoo 在使用否定运算符搜索 one2manymany2many 字段时的行为。想象一下,您有一个带有 A 标签的伙伴,并且您搜索 [('category_id.name', '!=', 'B')]。您的伙伴出现在结果中,这是您所期望的,但如果您向此伙伴添加 B 标签,它仍然会出现在您的结果中,因为对于搜索算法来说,存在一条不符合条件的链接记录(在本例中为 A)就足够了。现在,如果您删除 A 标签,以便 B 是唯一的标签,则该伙伴将被筛选掉。如果您也删除 B 标签,以便伙伴没有标签,它仍然会被筛选掉,因为链接记录的条件以存在此记录为前提。但是,在其他情况下,这是您想要的行为,因此更改标准行为并不是一个真正的选择。如果您在此处需要不同的行为,请提供一个搜索函数,以您需要的方式解释否定。

重要提示

人们经常忘记他们在编写 XML 文件时涉及到域。您需要转义小于运算符。搜索在当前日期之前创建的记录必须在 XML 中写为 [('create_date', '&lt;', current_date)]

域在 Odoo 中被广泛使用。您会在 Odoo 的任何地方找到它们;它们用于搜索、筛选、安全规则、搜索视图、用户动作等等。

如果您需要操作非以编程方式创建的域,请使用 odoo.osv.expression 中提供的实用函数。is_leafnormalize_domainANDOR 函数将允许您以 Odoo 完全相同的方式组合域。不要自己做,因为您必须考虑许多边界情况,而且您很可能会忽略一个。

参见

定义列表视图

在表单视图上花费了相当多的时间之后,我们现在快速查看一下如何定义列表视图。在内部,这些视图在某些地方称为树视图(tree views),在其他地方称为列表视图(list views),但鉴于 Odoo 视图框架内还有另一种称为(tree)的结构,我们在此处将坚持使用列表

如何实现…

  1. 定义您的列表视图:

  2. 在我们本章的《添加菜单项和窗口动作》小节中创建的动作中注册一个树视图:

  3. 添加调用这些动作的菜单。这留给读者作为练习。

安装/升级模块。之后,您将看到我们的旅馆房间的树视图,如果您查看它,它将根据我们的条件显示不同的行样式。

工作原理…

您已经知道这里发生的大部分事情。我们定义了一个视图,这次使用 tree 类型,并使用 ir.actions.act_window.view 元素将其附加到我们的动作。因此,剩下的唯一要讨论的是 tree 元素及其语义。对于列表,您没有太多的设计选择,因此此元素唯一有效的子项是 fieldbutton 元素。您也可以在列表视图中使用一些微件;在我们的示例中,我们使用了 many2one_avatar_user 微件。树视图支持一个称为 handle 的特殊微件。这是列表视图特有的。它适用于整数字段,并渲染一个拖动手柄,用户可以使用它将行拖动到列表中的不同位置,从而更新字段的值。这对于序列或优先级字段很有用。

通过使用可选属性,您可以选择性地显示字段。向字段添加 optional 属性将允许用户随时从 UI 中隐藏和显示该列。在我们的示例中,我们将其用于 countrystate 字段。

这里的新功能是 tree 元素中的 decoration 属性。这包含有关为行选择哪种字体和/或颜色的规则,以 decoration-$name="Python code" 的形式给出。我们使这些不可见,因为我们只需要数据,不想用两个额外的列来打扰用户。可能的类是 decoration-bf(粗体)和 decoration-it(斜体),语义 Bootstrap 类是 decoration-dangerdecoration-infodecoration-muteddecoration-primarydecoration-successdecoration-warning

更多内容…

对于数字字段,您可以添加一个 sum 属性,该属性会导致此列被求和,并在属性中设置的文本作为工具提示。不太常见的是 avgminmax 属性,它们分别显示平均值、最小值和最大值。请注意,这四个属性仅适用于当前可见的记录,因此您可能需要调整动作的 limit(前面在《添加菜单项和窗口动作》小节中介绍过),以便用户立即看到所有记录。

tree 元素一个非常有趣的属性是 editable。如果您将其设置为 topbottom,则列表的行为将完全不同。没有它,点击行会打开该行的表单视图。有了它,点击行会使其可内联编辑,可见字段渲染为表单字段。这在嵌入式列表视图中特别有用,本章后面的《定义嵌入式视图》小节中将对此进行讨论。topbottom 的选择与新行是添加到列表的顶部还是底部有关。

默认情况下,记录根据显示模型的 _order 属性进行排序。用户可以通过点击列标题来更改排序,但您也可以通过在 tree 元素中设置 default_order 属性来设置不同的初始顺序。语法与 _order 中的语法相同。

重要提示

排序通常是新开发人员感到沮丧的根源。由于 Odoo 在此处让 PostgreSQL 完成工作,您只能根据 PostgreSQL 知道的字段以及仅位于同一数据库表中的字段进行排序。因此,如果要根据函数或相关字段进行排序,请确保设置 store=True。如果您需要根据从另一个模型继承的字段进行排序,请声明一个存储的相关字段。

tree 元素的 createeditdelete 属性的工作方式与我们在本章的《向表单视图添加内容和微件》小节中描述的 form 元素的工作方式相同。如果设置了 editable 属性,它们也会决定可用的控件。

定义搜索视图

当您打开列表视图时,您会注意到右上角的搜索字段。如果您在那里键入内容,您将收到有关搜索内容的建议,并且还有一组预定义的筛选器可供选择。本小节将引导您完成如何定义这些建议和选项。

如何实现…

  1. 定义您的搜索视图:

  2. 告知您的动作使用它:

现在,当您在搜索栏中键入内容时,系统将为您提供在 nameroom nostate 字段中搜索此术语的功能。如果您的术语恰好是系统中银行帐号的子字符串,系统甚至会为您提供精确搜索此银行帐号的选项。

工作原理…

name 的情况下,我们只是将该字段列为提供给用户搜索的字段。我们将语义保留为默认值,即字符字段的子字符串搜索。

对于类别,我们做了一些更有趣的事情。默认情况下,您的搜索词应用于称为 name_searchmany2many 字段触发器,在这种情况下,它将是类别名称中的子字符串搜索。但是,根据您的类别结构,搜索具有您感兴趣的类别或其子项的伙伴可能会非常方便。想想一个主要类别 newsletter subscribers,其子类别为 weekly newslettermonthly newsletter 和其他几种通讯类型。使用前面的搜索视图定义搜索 newsletter subscribers 将使您一次获得订阅其中任何通讯的所有人,这比搜索每种类型并组合结果要方便得多。

filter_domain 属性可以包含任意域,因此您不仅限于搜索与 name 属性中命名的字段相同的字段,也不限于仅使用一个术语。self 变量是用户填写的内容,也是您可以在此处使用的唯一变量。

以下是 hostel room 的默认搜索视图中更详细的示例:

这意味着用户不必考虑要搜索什么。他们所需要做的就是输入一些字母,按 Enter 键,如果运气好的话,所提及的其中一个字段包含我们正在寻找的字符串。

对于 child_ids 字段,我们使用了另一个技巧。字段的类型不仅决定了搜索用户输入的默认方式,还定义了 Odoo 呈现建议的方式。此外,鉴于 many2one 字段是唯一提供自动完成功能的字段,我们通过设置 widget 属性来强制 Odoo 执行此操作,即使 child_ids 是一个 one2many 字段。没有这个,我们将不得不在此字段中搜索,而没有完成建议。这同样适用于 many2many 字段。

重要提示

请注意,设置了 many2one 微件的每个字段都会在用户的每次击键时触发对其模型的搜索;不要使用太多。

您还应该将最常用的字段放在顶部,因为如果用户只是键入内容并按 Enter 键,则会搜索第一个字段。搜索栏也可以与键盘一起使用;通过按向下箭头选择建议,并通过按向右箭头打开 many2one 的完成建议。如果您向用户介绍这一点并注意搜索视图中字段的合理顺序,这将比先键入内容、抓住鼠标然后选择选项要高效得多。

filter 元素创建了一个按钮,将筛选器的 domain 属性的内容添加到搜索域中。您应该添加一个逻辑内部名称和一个 string 属性来向用户描述筛选器。

<group> 标签用于在分组依据按钮下提供分组选项。在此小节中,我们添加了一个选项,用于根据 country_id 字段对记录进行分组。

更多内容…

您可以使用 group 标签对筛选器进行分组,这会导致它们渲染得比其他筛选器更靠近一些,但这也具有语义含义。如果您将多个筛选器放在同一组中并激活其中一个以上,它们的域将与 | 运算符组合,而不在同一组中的筛选器和字段将与 & 运算符组合。有时,您可能需要筛选器的析取,在这种情况下,它们会筛选互斥的集合,在这种情况下,选择它们都会始终导致空结果集。在同一组内,您可以使用 separator 元素实现相同的效果。

重要提示

请注意,如果用户为同一字段填写了多个查询,它们也将与 | 组合,因此您无需担心。

除了 field 属性之外,filter 元素还可以具有 context 属性,其内容将与当前上下文以及搜索视图中的其他上下文属性合并。这对于支持分组的视图(请参阅《定义看板视图》和《定义图表视图》小节)至关重要,因为生成的上下文决定了要使用 group_by 键分组的字段。我们将在适当的小节中研究分组的细节,但上下文还有其他用途。例如,您可以编写一个函数字段,它根据上下文返回不同的值,然后可以通过激活筛选器来更改值。

搜索视图本身也会响应上下文键。与创建记录时的默认值非常相似,您可以通过上下文传递搜索视图的默认值。如果我们先前在动作中设置了 {'search_default_room_rating': 1} 的上下文,则 room_rating 筛选器将在搜索视图中预选。但这仅在筛选器具有名称时才有效,这也是您应该始终设置它的原因。要在搜索视图中为字段设置默认值,请使用 search_default_$fieldname

此外,fieldfilter 元素可以具有 groups 属性,其语义与表单视图中的语义相同,以便使元素仅对某些组可见。

参见

添加搜索筛选器侧面板

Odoo 提供了另一种显示搜索筛选器的方法,即搜索筛选器侧面板。此面板在视图的侧面显示筛选器列表。当最终用户经常使用搜索筛选器时,搜索面板非常有用。

准备工作

搜索面板是搜索视图的一部分。因此,对于本小节,我们将继续使用上一个小节中的 my_module 附加模块。我们将把搜索面板添加到先前设计的搜索视图中。

如何实现…

在搜索视图中添加 <searchpanel>,如下所示:

更新模块以应用修改。更新后,您将在视图的左侧看到搜索面板。

工作原理…

要添加搜索面板,您需要在搜索视图中使用 <searchpanel> 标签。要添加筛选器,您需要在搜索面板中添加一个字段。

在我们的示例中,首先,我们添加了一个 state 字段。您还需要向该字段添加一个 icon 属性。此图标将显示在筛选器标题之前。将字段添加到搜索面板后,它将显示带有图标的标题,并在其下方显示所有用户的列表。单击用户后,列表视图中的记录将被筛选,您将只看到所选用户的联系人。在此筛选器中,只能激活一个项目,这意味着一旦您单击另一个用户的筛选器,前一个用户的筛选器将被删除。如果要激活多用户筛选器,可以使用 select="multi" 属性。如果您使用该属性,您将找到每个筛选器选项的复选框,并且您将能够一次激活多个筛选器。我们在 state 筛选器上使用了 select="multi" 属性。这将允许我们一次选择和筛选多个类别。

重要提示

在使用侧面板筛选器进行 many2onemany2many 时要小心。如果关系模型有太多记录,则只会显示前 200 条记录,以避免性能问题。

更多内容…

如果您想在组中显示搜索面板项目,您可以在字段上使用 groupby 属性。例如,如果您想根据父层次结构对类别进行分组,您可以添加带有 parent_id 字段的 groupby 属性,如下所示:

这将显示根据记录的父类别分组的类别筛选器。

更改现有视图 – 视图继承

到目前为止,我们忽略了现有视图并声明了全新的视图。虽然这在教学上是明智的,但您很少会遇到需要为现有模型定义新视图的情况。相反,您会希望稍微修改现有视图,无论是只是让它们显示您在附加模块中添加到模型的字段,还是根据您的需求或客户的需求自定义它们。

在本小节中,我们将通过修改搜索视图来更改默认伙伴表单以显示记录的上次修改日期,并使 mobile 字段可搜索。然后,我们将更改伙伴列表视图中一列的位置。

如何实现…

  1. 将字段注入默认表单视图:

  2. 将字段添加到默认搜索视图:

  3. 将字段添加到默认列表视图:

更新模块后,您应该在伙伴表单上的 website 字段下方看到 Last updated on 字段。当您在搜索框中键入内容时,它应该建议您搜索 mobile 字段上的伙伴,并且在伙伴的列表视图中,您将看到电话号码和电子邮件的顺序已更改。

工作原理…

在步骤 1 中,我们添加了表单继承的基本结构。正如您可能猜到的,这里的关键字段是 inherit_id。您需要将要修改(继承自)的视图的 XML ID 传递给它。arch 字段包含有关如何修改您正在继承的视图中现有 XML 节点的说明。您应该将整个过程视为简单的 XML 处理,因为所有语义部分都只会晚得多出现。

继承视图的 arch 字段中最规范的指令是 field 元素,它具有必需的属性:nameposition。由于每个字段只能在表单中出现一次,因此 name 已经唯一地标识了一个字段。使用 position 属性,我们可以将我们放入 field 元素内的任何内容放置在相对于我们命名的字段的之前内部之后。默认值是内部,但为了可读性,您应该始终命名您需要的位置。请记住,我们在这里不是在谈论语义;这是关于 XML 树中相对于我们命名的字段的位置。之后将如何渲染这是另一个完全不同的问题。

步骤 2 演示了另一种方法。xpath 元素选择与 expr 属性中命名的 XPath 表达式匹配的第一个元素。在这里,position 属性告诉处理器将 xpath 元素的内容放在哪里。

重要提示

如果您想基于 CSS 类创建 XPath 表达式,Odoo 提供了一个名为 hasclass 的特殊函数。例如,如果您想选择带有 test_class CSS 类的 <div> 元素,则表达式将是 expr="//div[hasclass('test_class')]"

步骤 3 显示了如何更改元素的位置。此选项是在版本 12 中引入的,很少使用。在我们的示例中,我们使用 position=move 选项将电话字段移动到电子邮件字段之后。

XPath 可能看起来有些可怕,但它是选择您需要处理的节点的非常有效的方法。花时间查看一些简单的表达式;这是值得的。您可能会偶然发现术语上下文节点(context node),一些表达式是相对于它的。在 Odoo 的视图继承系统中,这始终是您正在继承的视图的根元素。

对于继承视图的 arch 字段中找到的所有其他元素,处理器会查找具有相同节点名称和匹配属性的第一个元素(position 属性除外,因为它是指令的一部分)。仅在此组合极不可能不唯一的情况下使用此选项,例如与 name 属性组合的 group 元素。

重要提示

请注意,您可以在 arch 字段中拥有所需数量的指令元素。我们每个继承视图只使用了一个,因为目前我们没有其他要更改的内容。

更多内容…

position 属性还有另外两个可能的值:replaceattributes。使用 replace 会导致所选元素被指令元素的内容替换。因此,如果您没有任何内容,则可以简单地删除所选元素。前面的列表或表单视图将导致 state 字段被删除:

重要提示

删除字段可能会导致其他继承视图中断以及其他几个不良副作用,因此如果可能,请避免这样做。如果您确实需要删除字段,请在评估顺序中靠后的视图中执行此操作(请参阅下一节《视图继承中的评估顺序》了解更多信息)。

attributes 的语义与前面的示例非常不同。处理器期望该元素包含带有 name 属性的 attribute 元素。然后,这些元素将用于为所选元素设置属性。如果您想注意前面的警告,则应将 invisible 属性设置为 state 字段的 1

attribute 节点可以具有 addremove 属性,这些属性应包含要从空格分隔列表中删除或添加到其中的值。这对于 class 属性非常有用,您可以通过使用以下内容来添加类(而不是覆盖整个属性):

此代码将 oe_inline 类添加到 description 字段。如果该字段已存在 class 属性,Odoo 将使用 separator 属性的值连接该值。

视图继承中的评估顺序

由于我们目前只有一个父视图和一个继承视图,因此我们不会遇到冲突的视图覆盖问题。当您安装了几个模块时,您会发现伙伴表单有很多覆盖。只要它们更改视图中的不同内容,这就可以了,但在某些情况下,了解覆盖的工作原理以避免冲突非常重要。

视图的直接后代按其 priority 字段的升序进行评估,因此首先应用具有较低优先级的视图。继承的每一步都应用于第一个结果,因此如果优先级为 3 的视图更改了一个字段,而另一个优先级为 5 的视图将其删除,则这就可以了。但是,如果优先级颠倒,则这不起作用。

您还可以从视图本身继承一个继承视图。在这种情况下,第二级继承视图应用于它所继承的视图的结果。因此,如果您有四个视图:A、B、C 和 D,其中 A 是一个独立表单,B 和 C 继承自 A,D 继承自 B,则评估顺序是 A、B、D 和 C。使用此方法可以在不依赖优先级的情况下强制执行顺序;这通常更安全。如果继承视图添加了一个字段,并且您需要对该字段应用更改,请继承该继承视图,而不是独立视图。

重要提示

这种继承始终作用于原始视图的完整 XML 树,并应用了来自先前继承视图的修改。

以下几点提供了有关用于调整视图继承行为的一些高级技巧的信息:

定义文档风格的表单

在本小节中,我们将回顾一些设计准则,以便呈现统一的用户体验。

如何实现…

  1. 使用 header 元素开始您的表单:

  2. 添加一个 sheet 元素用于内容:

  1. 放入 stat 按钮,该按钮将用于显示旅馆房间总数并将重定向到旅馆房间:

  1. 添加一些突出显示的字段:

  1. 添加您的内容;如果有很多字段,您可以使用 notebook

  1. sheet 之后,添加 chatter 微件(如果适用):

让我们看看这个小节是如何工作的。

工作原理…

header 应该包含对用户当前看到的对象执行动作的按钮。使用 btn-primary 类使按钮在视觉上脱颖而出(在撰写本文时为紫色),这是指导用户当前最合乎逻辑的动作的好方法。尝试将所有突出显示的按钮放在非突出显示的按钮的左侧,并隐藏与当前状态不相关的按钮(如果适用)。如果模型具有状态,请使用 statusbar 微件在 header 中显示它。这将渲染为在 header 中右对齐。

sheet 元素渲染为程式化的工作表,最重要的字段应该是用户看到它的第一件事。使用 oe_title 类使它们在突出位置渲染(在撰写本文时浮动在左侧,字体大小略有调整)。

如果存在与用户当前看到的记录相关的其他感兴趣的记录(例如,伙伴表单上的伙伴发票),请将它们放入具有 oe_rightoe_button_box 类的元素中;这会将其中的按钮对齐到右侧。在按钮本身上,使用 oe_stat_button 类来强制按钮的统一渲染。通常还会为 icon 属性分配一个来自 Font Awesome 图标的图标类。您可以在 https://fontawesome.com/v4.7.0/icons/ 上了解有关 Font Awesome 的更多信息。

您可以使用 oe_chatter 类和 Chatter 微件在表单视图的底部获取默认的 Chatter。为此,您需要使用 mail.thread mixin。我们将在第 23 章《在 Odoo 中管理电子邮件》中详细介绍这一点。

重要提示

即使您不喜欢此布局,也要坚持此处描述的元素和类名称,并使用 CSS 和可能的 JavaScript 调整您需要的内容。这将使用户界面与现有附加模块更兼容,并允许您更好地与核心附加模块集成。

参见

使用属性的动态表单元素

到目前为止,我们只研究了根据用户组更改表单(元素的 groups 属性和继承视图的 groups_id 字段),仅此而已。本小节将向您展示如何根据表单中字段的值修改表单视图。

如何实现…

  1. 在表单元素上定义一个名为 attributes 的属性:

  1. 确保您引用的所有字段在表单中都可用:

如果 parent_id 不是旅馆房间类别,这将使 child_ids 字段不可见,如果是旅馆房间类别,则将是必需的。

工作原理…

attributes 包含一个带有 invisiblerequiredreadonly 键(所有这些都是可选的)的字典。这些值是域,可以引用表单上存在的字段(并且确实只有这些字段,因此没有点路径),并且整个字典根据本章前面的《向表单和动作传递参数 – 上下文》小节中描述的客户端 Python 规则进行评估。因此,例如,您可以在右侧操作数中访问上下文。

更多内容…

虽然此机制对于标量字段非常简单,但如何处理 one2manymany2many 字段就不那么明显了。事实上,在标准 Odoo 中,您不能在 attributes 中对这些字段做太多事情。但是,如果您只需要检查此类字段是否为空,请使用 [[6, False, []]] 作为您的右侧操作数。

定义嵌入式视图

当您在表单上显示 one2manymany2many 字段时,如果您没有使用专用微件,则对它的渲染方式没有太多控制权。此外,在 many2one 字段的情况下,有时需要能够影响链接记录的打开方式。在本小节中,我们将研究如何为这些字段定义私有视图。

如何实现…

  1. 像往常一样定义您的字段,但不要关闭标签:

  1. 将视图定义写入标签中:

  1. 关闭标签:

工作原理…

当 Odoo 加载表单视图时,它首先检查关系类型字段是否在字段中具有嵌入式视图,如前所述。这些嵌入式视图可以具有与我们之前定义的视图完全相同的元素。只有当 Odoo 没有找到某种类型的嵌入式视图时,它才会使用该模型的该类型的默认视图。

更多内容…

虽然嵌入式视图可能看起来是一个很棒的功能,但它们使视图继承复杂得多。例如,一旦涉及到嵌入式视图,字段名称就不能保证是唯一的,并且您通常必须使用一些复杂的 XPath 来选择嵌入式视图中的元素。

因此,通常,您最好定义独立视图并使用 form_view_reftree_view_ref 键,如本章前面的《让动作打开特定的视图》小节中所述。

在表单视图侧面显示附件

在某些应用程序(例如发票)中,您需要根据文档填写数据。为了简化数据填写过程,Odoo 12 版本添加了一项新功能,可在表单视图侧面显示文档。

在本小节中,我们将学习如何并排显示表单视图和文档:

图 9.3 – 级联附件和表单视图

重要提示

此功能仅适用于大型显示器(>1534px),因此如果您的视口较小,此功能将被隐藏。在内部,此功能使用一些响应式实用程序,因此此功能仅在企业版中有效。但是,您仍然可以在模块中使用此代码。Odoo 将自动处理此问题,因此如果模块安装在企业版中,它将显示文档,而在社区版中,它将隐藏所有内容而没有任何副作用。

如何实现…

我们将启用此功能来修改 hostel.room.category 模型的表单视图,如下所示:

更新模块以应用更改。您需要通过记录 Chatter 上传 PDF 或图像。当您上传它时,Odoo 将在侧面显示附件。

工作原理…

此功能仅在您的模型继承了 mail.thread 模型时才有效。要在任何表单视图的侧面显示文档,您需要在 chatter 元素之前添加一个带有 o_attachment_preview 类的空 <div>。就是这样;附加在 chatter 中的文档将显示在表单视图的侧面。

默认情况下,pdfimage 文档将按日期升序显示。您可以通过提供额外的选项来更改此行为,其中包括:

更多内容…

在大多数情况下,您希望在任何记录的初始状态的侧面显示文档。如果您想根据域隐藏附件预览,您可以使用 <div> 标签上的属性来隐藏预览。

查看以下示例:如果 state 字段的值不是 draft,它将隐藏 PDF 预览:

这就是您可以在不需要附件时隐藏附件的方式。通常,此功能用于从 PDF 填写数据,并且仅在草稿模式下激活。

定义看板视图

到目前为止,我们向您展示了可以打开以显示表单的记录列表。虽然这些列表在显示大量信息时很有效,但鉴于缺乏设计可能性,它们往往有点无聊。在本小节中,我们将看看看板视图(kanban views),它允许我们以更吸引人的方式呈现记录列表。

如何实现…

  1. 定义 kanban 类型的视图:

  2. 列出您将在视图中使用的字段:

  3. 实现设计:

  4. 关闭所有标签:

将此视图添加到您的一个动作中。这留给读者作为练习。您将在 GitHub 示例文件中找到一个完整的有效示例:https://github.com/PacktPublishing/Odoo-13-Development-Cookbook-Fourth-Edition/tree/master/Chapter09/15_kanban_view/my_module

工作原理…

我们需要在步骤 2 中给出要加载的字段列表,以便稍后能够访问它们。templates 元素的内容必须是一个 t 元素,其 t-name 属性设置为 kanban-box

您在此元素内编写的内容将针对每条记录重复,并具有 t 元素和 t-* 属性的特殊语义。有关此内容的详细信息,请参阅第 15 章《Web 客户端开发》中的《使用客户端 QWeb 模板》小节,因为从技术上讲,看板视图只是 QWeb 模板的应用。

有一些特定于看板视图的修改。您可以在评估期间访问 read_only_moderecordwidget 变量。可以使用 record.fieldname 访问字段,这是一个具有 valueraw_value 属性的对象,其中 value 是字段的值,已格式化为可呈现给用户的方式,而 raw_value 是字段的值,因为它来自数据库。

重要提示

many2many 字段在此处是一个例外。您只能通过 record 变量获得 ID 列表。对于用户可读的表示,您必须使用 field 元素。

请注意模板顶部链接的 type 属性。此属性使 Odoo 生成一个链接,该链接以查看模式 (open) 或编辑模式 (edit) 打开记录,或删除记录 (delete)。type 属性也可以是 objectaction,这将渲染调用模型中的函数或动作的链接。在这两种情况下,您都需要补充表单视图中按钮的属性,如本章的《向表单添加按钮》小节中所述。您可以改用 button 元素而不是 a 元素;type 属性在此处具有相同的语义。

更多内容…

还有一些值得一提的辅助函数。如果您需要为元素生成伪随机颜色,请使用 kanban_color(some_variable) 函数,它将返回一个设置背景和颜色属性的 CSS 类。这通常用于 t-att-class 元素中。

如果您想显示存储在二进制字段中的图像,请使用 kanban_image(modelname, fieldname, record.id.raw_value),如果您将该字段包含在字段列表中,它将返回一个数据 URI;如果未设置该字段,则是一个占位符;或者,如果您未将该字段包含在字段列表中,则是一个使 Odoo 流式传输该字段内容的 URL。如果您需要同时显示大量记录或如果您期望非常大的图像,请不要将该字段包含在字段列表中。通常,您会在 img 元素的 t-att-src 属性中使用此功能。

重要提示

在看板视图中进行设计可能会有点困难。通常,更好的方法是使用 HTML 类型的函数字段生成 HTML,并从 Qweb 视图生成此 HTML。通过这种方式,您仍然在执行 QWeb,但是在服务器端执行,当您需要处理大量数据时,这会方便得多。

参见

根据其状态在列中显示看板卡片

本小节向您展示如何设置看板视图,用户可以在其中将记录从一列拖放到另一列,从而将相关记录推送到另一种状态。

准备工作

从现在开始,我们将在此处使用 hostel 模块,因为它定义的模型比基本模块中定义的模型更适合基于日期和状态的视图。因此,在继续之前,请将 base 添加到您的附加模块的依赖项列表中。

如何实现…

  1. hostel room category 定义一个看板视图:

  2. 添加使用此视图的菜单和动作。这留给读者作为练习。

工作原理…

看板视图支持分组,这允许您将具有相同组字段值的记录显示在同一列中。这通常用于父旅馆房间类别或 parent_id 字段,因为它允许用户通过简单地将记录拖动到另一列来更改记录的此字段的值。将 kanban 元素的 default_group_by 属性设置为要分组的字段名称,以利用此功能。

要控制看板分组的行为,Odoo 中提供了一些选项:

更多内容…

如果未在专用属性中定义,则任何搜索筛选器都可以通过将名为 group_by 的上下文键设置为要分组的字段名称来添加分组。

定义日历视图

本小节将引导您完成如何以可视化方式显示和编辑记录中的日期和持续时间信息。

如何实现…

请按照以下步骤为 hostel.room.category 模型添加日历视图:

  1. 定义日历视图:

  1. 添加使用此视图的菜单和动作。这留给读者作为练习。

工作原理…

日历视图需要将字段名称传递给 date_startdate_stop 属性,以指示在构建可视化表示时要查看哪些字段。仅使用 DatetimeDate 类型的字段;其他类型的字段将不起作用并会生成错误。虽然 date_start 是必需的,但您可以省略 date_stop 并改为设置 date_delay 属性,该属性预计是一个表示持续时间(以小时为单位)的浮点字段。

日历视图允许您为在一个字段中具有相同值的记录赋予相同的(任意分配的)颜色。要使用此功能,请将 color 属性设置为您需要的字段的名称。在我们的示例中,我们可以一目了然地看到哪个旅馆房间类别属于同一旅馆房间类别,因为我们将 parent_id 分配为确定颜色组的字段。

您在 calendar 元素正文中命名的字段显示在代表所涵盖时间间隔的块内,并用逗号分隔。

更多内容…

日历视图还有一些其他有用的属性。如果您想在弹出窗口而不是标准表单视图中打开日历条目,请将 event_open_popup 设置为 1。默认情况下,您只需填写一些文本即可创建新条目,这在内部调用模型的 name_create 函数来实际创建记录。如果您想禁用此行为,请将 quick_add 设置为 0

如果您的模型涵盖一整天,请将 all_day 设置为字段的名称,如果记录涵盖一整天,则为 true,否则为 false

定义图表视图和透视表视图

在本小节中,我们将看看 Odoo 的商业智能视图。这些是旨在呈现数据的只读视图。

准备工作

我们仍在使用 hostel 模块。您可以配置图表视图和透视表视图以获取不同的统计信息。对于我们的示例,我们将重点关注已分配的用户。我们将生成一个图表视图和透视表视图,以查看旅馆房间类别的用户。顺便说一句,最终用户可以通过修改视图选项来生成他们选择的统计信息。

如何实现…

  1. 定义使用柱状图的图表视图:

  2. 定义一个透视表视图:

  3. 添加使用此视图的菜单和动作。这留给读者作为练习。

如果一切顺利,您应该会看到图表,显示分配给哪个旅馆房间类别的父旅馆房间类别数量以及这些旅馆房间类别的状态。

工作原理…

图表视图是用根元素 graph 声明的。graph 元素上的 type 属性决定了图表视图的初始模式。可能的值是 barlinechart,但 bar 是默认值。图表视图是高度交互式的,因此用户可以在不同模式之间切换,也可以添加和删除字段。如果使用 type="bar",您还可以使用 stacked="1" 在分组期间显示堆叠条形图。

field 元素告诉 Odoo 在哪个轴上显示什么。对于所有图表模式,您至少需要一个 row 类型的字段和一个 measure 类型的字段才能看到任何有用的内容。row 类型的字段决定了分组,而 measure 类型的字段代表要显示的值。折线图只支持每种类型一个字段,而图表和条形图可以很好地处理两个组字段和一个度量。

透视表视图有自己的根元素 pivot。透视表视图支持任意数量的组和度量字段。如果您切换到不支持您定义的组和度量数量的模式,则不会中断;有些字段只会被忽略,结果可能不如您想象的那么有趣。

更多内容…

对于所有图表类型,Datetime 字段很难分组,因为您很少会遇到相同的字段值。因此,如果您有一个 row 类型的 Datetime 字段,请同时指定带有以下值之一的 interval 属性:dayweekmonthquarteryear。这将导致分组在给定的时间间隔内进行。

重要提示

分组与排序一样,严重依赖 PostgreSQL。因此,这里的规则也适用,即字段必须存在于数据库中并且存在于当前表中才能使用。

一种常见的做法是定义数据库视图,收集您需要的所有数据,并在该视图之上定义一个模型,以便拥有所有必要的字段。

根据视图的复杂性和分组,构建图表可能是一项非常昂贵的任务。在这些情况下,请考虑将 auto_search 属性设置为 False,以便用户可以首先调整所有参数,然后才触发搜索。

透视表还支持列中的分组。对您希望在那里拥有的字段使用 col 类型。

定义同期群视图

为了对记录进行同期群分析,Odoo 12 版本中添加了新的同期群视图。同期群视图用于找出记录在特定时间跨度内的生命周期。使用同期群视图,您可以查看任何对象在特定时间内的流失率和保留率。

准备工作

同期群视图是 Odoo 企业版的一部分,因此您不能仅使用社区版。如果您使用的是企业版,您需要将 web_cohort 添加到模块的清单文件中。对于我们的示例,我们将创建一个视图以查看旅馆房间类别的同期群分析。

如何实现…

请按照以下步骤为 hostel.room.category 模型添加同期群视图:

  1. 定义同期群视图:

  2. 添加使用此视图的菜单和动作。这留给读者作为练习。

工作原理…

要创建同期群视图,您需要提供 date_startdate_stop。这些将用于视图中以确定任何记录的时间跨度。例如,如果您正在管理服务的订阅,则订阅的开始日期将是 date_start,订阅将到期的日期将是 date_stop

默认情况下,同期群视图将以保留模式按月间隔显示。您可以使用给定的选项在同期群视图中获得不同的行为:

定义甘特图视图

Odoo 13 版本添加了一个新的甘特图视图,带有新选项。甘特图视图对于查看总体进度和调度业务流程非常有用。在本小节中,我们将创建一个新的甘特图视图并查看其选项。

准备工作

甘特图视图是 Odoo 企业版的一部分,因此您不能将它与社区版一起使用。如果您使用的是企业版,则需要在模块的清单文件中添加 web_gantt 依赖项。

在我们的示例中,我们将继续使用上一个小节中的 my_hostel 模块。我们将为旅馆房间类别创建一个新的甘特图视图。

如何实现…

  1. 为旅馆房间类别模型定义甘特图视图,如下所示:

  2. 添加使用此视图的菜单和动作。这留给读者作为练习。

安装并更新模块以应用更改;更新后,您将在旅馆房间类别上看到甘特图视图。

工作原理…

使用甘特图视图,您可以在一个屏幕上显示总体计划。在我们的示例中,我们为按父级分组的旅馆房间类别创建了一个甘特图视图。通常,您需要两个属性来创建甘特图视图:start_datestop_date,但还有一些其他属性可以扩展甘特图视图的功能。让我们看看所有选项:

默认情况下,甘特图视图项目是可调整大小和可拖动的,但如果您想禁用它,可以使用 edit="0" 属性。

更多内容…

当您将鼠标悬停在甘特图视图项目上时,您将看到项目的名称和日期。如果您想自定义该弹出窗口,您可以在甘特图视图定义中定义一个 QWeb 模板,如下所示:

请注意,您需要通过 <field> 标签添加要用于模板的字段。

定义活动视图

活动是 Odoo 应用程序的重要组成部分。它们用于为不同的业务对象调度待办动作。活动视图可帮助您查看模型上所有活动的状态和计划。

准备工作

在我们的示例中,我们将继续使用上一个小节中的 my_hostel 模块。我们将为旅馆房间类别创建一个新的活动视图。

如何实现…

  1. 为旅馆房间类别模型定义活动视图,如下所示:

  1. 添加使用此视图的菜单和动作。这留给读者作为练习。

工作原理…

活动视图很简单;大多数事情都是自动管理的。您只需选择自定义第一列。要在第一列中显示您的数据,您需要创建一个名为 activity-box 的 QWeb 模板,仅此而已;Odoo 将管理其余部分。

活动视图将在第一列中显示您的模板,其他列将显示按活动类型分组的计划活动。

定义地图视图

Odoo 13 版本添加了一个名为地图视图(map view)的新视图。顾名思义,它用于显示带有标记的地图。它们对于现场服务非常有用。

准备工作

在我们的示例中,我们将继续使用上一个小节中的 my_hostel 模块。我们将为旅馆房间类别创建新的地图视图。地图视图是 Odoo 企业版的一部分,因此您不能将它与社区版一起使用。如果您使用的是企业版,则需要在模块的清单文件中添加 web_map 依赖项。

Odoo 使用来自 https://www.mapbox.com/ 的 API 在视图中显示地图。为了在 Odoo 中看到地图,您需要从 mapbox 生成访问令牌。确保您已生成访问令牌并将其设置在 Odoo 配置中。

如何实现…

  1. 为旅馆房间类别模型定义地图视图,如下所示:

  2. 添加使用此视图的菜单和动作。这留给读者作为练习。

工作原理…

创建地图视图非常简单;您只需要一个引用 hostel.room.category 模型的多对一字段。hostel.room.category 模型具有地址字段,地图视图使用这些字段来显示地址的标记。您需要使用 res_partner 属性来映射地图视图的地址。在我们的案例中,我们使用了 parent_id 字段作为在 parent_id 字段中设置的旅馆房间类别父记录集。

退出移动版