第四章:从头开始创建视图

警告

强烈建议在开始本章之前完成 第一章:字段和视图。第3章介绍的概念,包括视图和示例,对于理解本章所涵盖的内容至关重要。

让我们看看如何完全从头开始创建一个新视图。从某种意义上说,这并不是很难,但是没有真正好的资源来说明如何做到这一点。请注意,大多数情况应该通过定制现有视图或使用客户端操作来解决。

对于这个练习,让我们假设我们想要创建一个 gallery 视图,这是一个可以用图像字段表示一组记录的视图。在我们令人惊叹的 T 恤情景中,我们希望能够看到一组 T 恤图像。

这个问题当然可以通过看板视图来解决,但这意味着我们不能在同一个操作中同时使用普通看板视图和画廊视图。

让我们创建一个图库视图。每个图库视图将由其 arch 中的 image_field 属性定义:

<gallery image_field="some_field"/>

为了完成本章的任务,您需要安装awesome_gallery插件。该插件包含必要的服务器文件以添加新视图。

目标

../../../_images/overview1.png

本章的每个练习的解决方案都托管在 官方Odoo教程存储库

1. 创建一个 Hello World 视图

第一步是创建一个带有简单组件的JavaScript实现。

Exercise

  1. static/src 中创建 gallery_view.jsgallery_controller.jsgallery_controller.xml 文件。

  2. gallery_controller.js 中实现一个简单的 hello world 组件。

  3. gallery_view.js 中,导入控制器,创建一个视图对象,并将其注册到视图注册表中,名称为 gallery

  4. 在订单操作中添加 gallery 作为一种视图类型。

  5. 确保在切换到图库视图时,您可以看到您的hello world组件。

../../../_images/view_button.png ../../../_images/new_view.png

2. 使用布局组件

到目前为止,我们的图库视图看起来不像是一个标准视图。让我们使用 Layout 组件来拥有其他视图的标准功能。

Exercise

  1. 导入 Layout 组件并将其添加到 GalleryControllercomponents 中。

  2. 更新模板以使用 Layout。它需要一个 display 属性,可以在 props.display 中找到。

../../../_images/layout.png

3. 解析 arch

目前,我们的图库视图还没有做太多事情。让我们从阅读视图中包含的结构信息开始。

解析arch的过程通常使用 ArchParser 来完成,它是每个视图特定的。它继承自一个通用的 XMLParser 类。

Example

这是一个 ArchParser 可能看起来像的例子:

import { XMLParser } from "@web/core/utils/xml";

export class GraphArchParser extends XMLParser {
    parse(arch, fields) {
       const result = {};
       this.visitXML(arch, (node) => {
           ...
        });
       return result;
    }
}

Exercise

  1. 在自己的文件中创建 ArchParser 类。它可以继承自 @web/core/utils/xml 中的 XMLParser

  2. 使用它来读取 image_field 信息。

  3. 更新 gallery 视图代码,将其添加到控制器接收的 props 中。

注解

这样做可能有点过度设计,因为我们基本上只需要从arch中读取一个属性,但这是每个Odoo视图都使用的设计,因为它让我们将一些前期处理从控制器中提取出来。

4. 加载一些数据

现在让我们获取一些真实数据。

Exercise

  1. GalleryController 中添加一个 loadImages(domain) {...} 方法。它 应该执行一个来自 orm 服务的 webSearchRead 调用,以获取与域相对应的记录 并使用在 props 中接收到的 imageField

  2. 修改 setup 代码,在 onWillStartonWillUpdateProps 钩子中调用该方法。

  3. 修改模板以在 Layout 组件的默认插槽中显示数据。

注解

加载数据的代码将在下一个练习中移入适当的模型中。

../../../_images/gallery_data.png

5. 重新组织代码

真正的视图会更加有组织。在这个例子中可能有些过度,但这是为了学习如何在Odoo中构建代码结构。此外,这将更好地适应不断变化的需求。

Exercise

  1. 将所有模型代码移动到自己的 GalleryModel 类中。

  2. 将所有渲染代码移动到 GalleryRenderer 组件中。

  3. 调整 GalleryControllergallery_view 以使其正常工作。

6. 显示图片

Exercise

更新渲染器以便以美观的方式显示图像,如果字段已设置。如果 image_field 为空,则显示一个空框。

../../../_images/tshirt_images.png

7. 点击后切换到表单视图

Exercise

更新渲染器以响应对图像的单击并切换到表单视图。您可以使用操作服务中的 switchView 函数。

8. 添加一个可选的工具提示

鼠标悬停时提供一些额外的信息是有用的。

Exercise

  1. 更新代码以允许在arch上添加一个可选的附加属性:

    <gallery image_field="some_field" tooltip_field="some_other_field"/>
    
  2. 鼠标悬停时,显示工具提示字段的内容。如果该字段是字符字段、数字字段或many2one字段,则应该可以正常工作。

  3. 更新订单画廊视图,将客户添加为工具提示字段。

../../../_images/image_tooltip.png

9. 添加分页功能

Exercise

让我们在控制面板上添加一个分页器,并像在普通的Odoo视图中一样管理所有分页。请注意,这是非常困难的。

../../../_images/pagination.png

10. 验证视图

到目前为止,我们已经拥有了一个漂亮且有用的视图。但在实际应用中,我们可能会遇到用户错误编码其图库视图的 arch 的问题:它目前只是一个非结构化的 XML 片段。

让我们添加一些验证!在Odoo中,XML文档可以用一个RN文件 :dfn:`(Relax NG文件)`来描述,然后进行验证。

Exercise

  1. 添加一个描述当前语法的 RNG 文件:

    • 一个必填属性 image_field.

    • 一个可选属性: tooltip_field

  2. 添加一些代码,确保所有视图都根据此 RNG 文件进行验证。

  3. 顺便提一下,确保 image_fieldtooltip_field 是当前模型中的字段。

由于验证 RNG 文件并不容易,这里提供了一个代码片段以帮助您:

# -*- coding: utf-8 -*-
import logging
import os

from lxml import etree

from odoo.loglevels import ustr
from odoo.tools import misc, view_validation

_logger = logging.getLogger(__name__)

_viewname_validator = None

@view_validation.validate('viewname')
def schema_viewname(arch, **kwargs):
    """ Check the gallery view against its schema

    :type arch: etree._Element
    """
    global _viewname_validator

    if _viewname_validator is None:
        with misc.file_open(os.path.join('modulename', 'rng', 'viewname.rng')) as f:
            _viewname_validator = etree.RelaxNG(etree.parse(f))

    if _viewname_validator.validate(arch):
        return True

    for error in _viewname_validator.error_log:
        _logger.error(ustr(error))
    return False