跳到主要内容

create a new view

创建一个新的视图涉及的主要内容如下:

  • OWL
    • Controller
    • Renderer
    • Model
    • Arch Parser
    • View
  • Python
    • add the view_mode to 'ir.actions.act_window.view'
    • add the type to 'ir.ui.view'

create the Controller

Controller的主要作用是促进视图的各个组件之间的协调,例如 Renderer、Model 和 Layout。

Controller.js
/** @odoo-module */

import { Layout } from "@web/search/layout";
import { useService } from "@web/core/utils/hooks";
import { Component, onWillStart, useState} from "@odoo/owl";

export class BeautifulController extends Component {
setup() {
this.orm = useService("orm");

// The controller create the model and make it reactive so whenever this.model is
// accessed and edited then it'll cause a rerendering
this.model = useState(
new this.props.Model(
this.orm,
this.props.resModel, // from custom Model
this.props.fields, // from custom Model
this.props.archInfo, // from custom ArchParser
this.props.domain // from custom Model
)
);

onWillStart(async () => {
await this.model.load();
});
}
}

BeautifulController.template = "my_module.View";
BeautifulController.components = { Layout };

Controller的template带有Layout的control panel以及renderer。

controller.xml
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="my_module.View">
<Layout display="props.display" className="'h-100 overflow-auto'">
<t t-component="props.Renderer" records="model.records" propsYouWant="'Hello world'"/>
</Layout>
</t>
</templates>

create the Renderer

Renderer的主要功能是通过渲染包含记录的视图来生成数据的可视化展示。

renderer.js
import { Component } from "@odoo/owl";
export class BeautifulRenderer extends Component {}

BeautifulRenderer.template = "my_module.Renderer";
renderer.xml
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="my_module.Renderer">
<t t-esc="props.propsYouWant"/>
<t t-foreach="props.records" t-as="record" t-key="record.id">
// Show records
</t>
</t>
</templates>

create the Model

Model的作用是检索和管理视图中的所有必要的数据。

model.js
/** @odoo-module */

import { KeepLast } from "@web/core/utils/concurrency";

export class BeautifulModel {
constructor(orm, resModel, fields, archInfo, domain) {
this.orm = orm;
this.resModel = resModel;
// We can access arch information parsed by the beautiful arch parser
const { fieldFromTheArch } = archInfo;
this.fieldFromTheArch = fieldFromTheArch;
this.fields = fields;
this.domain = domain;
this.keepLast = new KeepLast();
}

async load() {
// The keeplast protect against concurrency call
const { length, records } = await this.keepLast.add(
this.orm.webSearchRead(this.resModel, this.domain, [this.fieldsFromTheArch], {})
);
this.records = records;
this.recordsLength = length;
}
}
提示

对于高级情况,除了从头开始创建模型,还可以使用其他视图使用的 RelationalModel。

create the arch parser

ArchParser的作用是解析arch视图,以便视图可以访问这些信息。

arch_parser.js
/** @odoo-module */

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

export class BeautifulArchParser extends XMLParser {
// 此处parse接收的参数来源于View的props()中的new ArchParser().parse()传参
parse(arch) {
const xmlDoc = this.parseXML(arch);
const fieldFromTheArch = xmlDoc.getAttribute("fieldFromTheArch");
return {
fieldFromTheArch,
};
}
}

Create the view and combine all the pieces together

创建视图将以上所有部分组合起来,然后注册视图。

view.js
/** @odoo-module */

import { registry } from "@web/core/registry";
import { BeautifulController } from "./beautiful_controller";
import { BeautifulArchParser } from "./beautiful_arch_parser";
import { BeautifylModel } from "./beautiful_model";
import { BeautifulRenderer } from "./beautiful_renderer";

export const beautifulView = {
type: "beautiful",
display_name: "Beautiful",
icon: "fa fa-map-o", // the icon that will be displayed in the Layout panel
multiRecord: true,
Controller: BeautifulController,
ArchParser: BeautifulArchParser,
Model: BeautifulModel,
Renderer: BeautifulRenderer,

props(genericProps, view) {
const { ArchParser } = view;
const { arch } = genericProps;
const archInfo = new ArchParser().parse(arch);

return {
...genericProps,
Model: view.Model,
Renderer: view.Renderer,
archInfo,
};
},
};

registry.category("views").add("beautifulView", beautifulView);

Add the view_mode to ir.actions.act_window.view

# -*- coding: utf-8 -*-
from odoo import fields, models


class ActWindowView(models.Model):
_inherit = 'ir.actions.act_window.view'

view_mode = fields.Selection(selection_add=[
('map', "Map")
], ondelete={'map': 'cascade'})

Add the type to ir.ui.view

# -*- coding: utf-8 -*-
from odoo import fields, models


class View(models.Model):
_inherit = 'ir.ui.view'

type = fields.Selection(selection_add=[('map', "Map View")])

Use view

...
<record id="my_beautiful_view" model="ir.ui.view">
<field name="name">my_view</field>
<field name="model">my_model</field>
<field name="arch" type="xml">
<beautiful>
...
</beautiful>
</field>
</record>
...