odoo17 | 模型视图继承

前言

Odoo的强大之处在于它的模块化。模块专门用于满足业务需求,但模块也可以彼此交互。这对于扩展现有模块的功能非常有用。例如,在我们的房地产场景中,我们希望在常规用户视图中直接显示销售人员的属性列表。

但是在讨论特定的Odoo模块继承之前,让我们看看如何更改标准CRUD(创建、检索、更新或删除)方法的行为。

Python 继承

目标

  • 设定不能删除非新建或已取消的属性。
    在这里插入图片描述
  • 创建产品/服务后,属性状态应更改为“已收到产品/服务”
  • 不能创建一个比现有报价更低的报价
    在这里插入图片描述
    在我们的房地产模块中,我们不需要开发任何特定的东西来执行标准的CRUD操作。Odoo框架提供了完成这些任务所需的工具。事实上,由于经典的Python继承,这些操作已经包含在我们的模型中:
from odoo import fields, models

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

    ...

我们的类TestModel继承自提供create()、read()、write()unlink()功能的models.Model

这些方法(以及Model类上定义的任何其他方法)可以扩展以添加特定的业务逻辑:

from odoo import fields, models

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

    ...

    @api.model
    def create(self, vals):
        # 做一些业务逻辑,修改值…
        ...
        # 然后调用super来执行父方法
        return super().create(vals)

装饰器model()对于create()方法是必需的,因为记录集本身的内容与创建上下文无关,但对于其他CRUD方法则不是必需的。

同样重要的是要注意,尽管我们可以直接覆盖**unlink()方法,但您几乎总是希望用ondelete()装饰器来编写一个新方法。带有此装饰符的方法将在unlink()期间被调用,从而避免了当unlink()**被直接覆盖时卸载模型模块时可能出现的一些问题。

Python 3中,super()等价于super(TestModel, self)。当您需要使用修改后的记录集调用父方法时,后者可能是必需的。

注意

总是调用super()以避免中断流程是非常重要的。只有一些非常特殊的情况下你用调用super()。

确保始终返回与父方法一致的数据。例如,如果父方法返回dict(),则重写也必须返回dict()。

模型继承

在我们的房地产模块中,我们希望显示与销售人员相关的房地产列表 直接在“设置”/“用户和公司”/“用户”窗体视图中。为此,我们需要将一个字段添加到 模型并调整其视图以显示它。res.users

Odoo提供了两种继承机制,以模块化方式扩展现有模型。

第一种继承机制允许模块通过以下方式修改另一个模块中定义模型的行为

  • 向模型添加字段,

  • 覆盖模型中字段的定义,

  • 向模型添加约束,

  • 向模型添加方法,

  • 重写模型中的现有方法。

第二种继承机制(委托)允许模型的每个记录链接到父模型的记录,并提供对该父记录字段的透明访问。

在这里插入图片描述

在Odoo中,第一种机制是目前使用最多的。在我们的示例中,我们希望向现有模型添加一个字段,这意味着我们将使用第一种机制。例如:

from odoo import fields, models

class InheritedModel(models.Model):
    _inherit = "inherited.model"

    new_field = fields.Char(string="New Field")

可以在此处找到向模型添加两个字段的实际示例。

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo import models, fields, api, _


class AccountMove(models.Model):
    _inherit = 'account.move'

    def _post(self, soft=True):
        vendor_bill_service = self.env.ref('account_fleet.data_fleet_service_type_vendor_bill', raise_if_not_found=False)
        if not vendor_bill_service:
            return super()._post(soft)

        val_list = []
        log_list = []
        not_posted_before = self.filtered(lambda r: not r.posted_before)
        posted = super()._post(soft)  # We need the move name to be set, but we also need to know which move are posted for the first time.
        for line in (not_posted_before & posted).line_ids.filtered(lambda ml: ml.vehicle_id):
            val = {
                'service_type_id': vendor_bill_service.id,
                'vehicle_id': line.vehicle_id.id,
                'amount': line.price_subtotal,
                'vendor_id': line.partner_id.id,
                'description': line.name,
            }
            log = _('Service Vendor Bill: <a href=# data-oe-model=account.move data-oe-id={move_id}>{move_name}</a>').format(
                move_id=line.move_id.id,
                move_name=line.move_id.name,
            )
            val_list.append(val)
            log_list.append(log)
        log_service_ids = self.env['fleet.vehicle.log.services'].create(val_list)
        for log_service_id, log in zip(log_service_ids, log_list):
            log_service_id.message_post(body=log)
        return posted


class AccountMoveLine(models.Model):
    _inherit = 'account.move.line'

    vehicle_id = fields.Many2one('fleet.vehicle', string='Vehicle')
    need_vehicle = fields.Boolean(compute='_compute_need_vehicle',
        help="Technical field to decide whether the vehicle_id field is editable")

    def _compute_need_vehicle(self):
        self.need_vehicle = False

按照惯例,每个继承的模型都在自己的Python文件中定义。在我们的例子中,它将是models/inherited_model.py。

视图继承

目标

  • 链接到销售人员的可用属性列表应显示在其用户窗体视图中
    在这里插入图片描述
    Odoo不是对现有视图进行修改(通过覆盖它们),而是提供视图继承,其中子“扩展”视图应用于根视图之上。这些扩展既可以添加也可以从父视图删除内容。

扩展视图使用 inherit_id 字段引用其父视图。与其单个视图不同,其 arch 字段包含多个 xpath 元素,用于选择和更改其父视图的内容

<record id="inherited_model_view_form" model="ir.ui.view">
    <field name="name">inherited.model.form.inherit.test</field>
    <field name="model">inherited.model</field>
    <field name="inherit_id" ref="inherited.inherited_model_view_form"/>
    <field name="arch" type="xml">
        <!-- find field description and add the field
             new_field after it -->
        <xpath expr="//field[@name='description']" position="after">
          <field name="new_field"/>
        </xpath>
    </field>
</record>

expr 表达式

一个XPath表达式,用于选择父视图中的一个元素。如果它没有匹配任何元素或匹配多个元素,则引发错误

position

应用于匹配元素的运算:

inside 在…内

将xpath的body附加到匹配元素的末尾

replace 代替

用xpath的body替换匹配的元素,将新body中出现的任何$0节点替换为原始元素

before 之前

将xpath的body作为同级插入到匹配的元素之前

after 之后

将xpath的body作为匹配元素之后的同级元素插入

attributes 属性,特征

使用XPath主体中的特殊属性元素更改匹配元素的属性

当匹配单个元素时,可以直接在要查找的元素上设置position属性。下面的两个继承具有相同的结果。

<xpath expr="//field[@name='description']" position="after">
    <field name="idea_ids" />
</xpath>

<field name="description" position="after">
    <field name="idea_ids" />
</field>

可以在这里找到一个视图继承扩展的示例。

<?xml version='1.0' encoding='utf-8'?>
<odoo>
    <record id="view_move_form" model="ir.ui.view">
        <field name="name">account.move.form</field>
        <field name="model">account.move</field>
        <field name="inherit_id" ref="account.view_move_form"/>
        <field name="arch" type="xml">
            <xpath expr="//field[@name='line_ids']//field[@name='account_id']" position="after">
                <field name='need_vehicle' invisible='1'/>
                <field name='vehicle_id' attrs="{'required': [('need_vehicle', '=', True), ('parent.move_type', '=', 'in_invoice')], 'column_invisible': [('parent.move_type', '!=', 'in_invoice')]}" optional='hidden'/>
            </xpath>
            <xpath expr="//field[@name='invoice_line_ids']//field[@name='account_id']" position="after">
                <field name='need_vehicle' invisible='1'/>
                <field name='vehicle_id' attrs="{'required': [('need_vehicle', '=', True), ('parent.move_type', '=', 'in_invoice')], 'column_invisible': [('parent.move_type', '!=', 'in_invoice')]}" optional='hidden'/>
            </xpath>
        </field>
    </record>
</odoo>

在下一章中,我们将学习如何 与其他模块交互。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/299899.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HackTheBox - Medium - Linux - UpDown

UpDown UpDown 是一台中等难度的 Linux 机器&#xff0c;暴露了 SSH 和 Apache 服务器。在Apache服务器上&#xff0c;有一个Web应用程序&#xff0c;允许用户检查网页是否已启动。服务器上标识了一个名为“.git”的目录&#xff0c;可以下载以显示目标上运行的“dev”子域的源…

GA算法简介

GA算法简介 前言一、GA是什么二、GA简介1.思想2.流程3.过程 前言 今天学习一下优化中非常出名的遗传(GA)算法 &#xff0c;它的起源可是来自达尔文的生物进化论。 一、GA是什么 百科定义&#xff1a;遗传算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;最早是…

Java多线程技术11——ThreadPoolExecutor类的使用1-备份

1 概述 ThreadPoolExecutor类可以非常方便的创建线程池对象&#xff0c;而不需要程序员设计大量的new实例化Thread相关的代码。 2 队列LinkedBlockingQueue的使用 public class Test1 {public static void main(String[] args) {LinkedBlockingQueue queue new LinkedBlocki…

四则运算 C语言xdoj20

问题描述&#xff1a; 输入两个整数和一个四则运算符&#xff0c;根据运算符计算并输出其运算结果&#xff08;和、差、积、商、余之一&#xff09;。注意做整除及求余运算时&#xff0c;除数不能为零。 输入说明&#xff1a; 使用scanf()函数输入两个整数和一个运算符&#xf…

【好书推荐】深入理解现代JavaScript

目录 推荐理由内容简介本书阅读对象为什么推荐这本书&#xff0c;看大佬们怎么说总结 T. J. Crowder是一位拥有30年经验的软件工程师。在他的整个职业生涯中&#xff0c;他至少有一半时间是在使用JavaScript从事开发工作。他经营着软件承包和产品公司Farsight Software。他经常…

工业协议转换网关:打破通信壁垒,实现设备互联

在工业自动化领域&#xff0c;各种设备和系统间的通信协议不尽相同&#xff0c;这给不同设备间的集成和数据交互带来了挑战。工业协议转换网关作为一种解决这一问题的关键设备&#xff0c;能够实现不同协议间的转换和数据传输&#xff0c;打破通信壁垒&#xff0c;提高设备的协…

2.8 EXERCISES

如果我们想使用每个线程来计算向量加法的一个输出元素&#xff0c;那么将线程/块索引映射到数据索引的表达式是什么&#xff1f; 答&#xff1a;C 假设我们想用每个线程来计算向量加法的两个&#xff08;相邻&#xff09;元素。将线程/块索引映射到i&#xff08;由线程处理的…

SpringSecurity集成JWT实现后端认证授权保姆级教程-数据准备篇

&#x1f341; 作者&#xff1a;知识浅谈&#xff0c;CSDN签约讲师&#xff0c;CSDN博客专家&#xff0c;华为云云享专家&#xff0c;阿里云专家博主 &#x1f4cc; 擅长领域&#xff1a;全栈工程师、爬虫、ACM算法 &#x1f492; 公众号&#xff1a;知识浅谈 &#x1f525;网站…

进阶学习——Linux系统安全及应用

目录 一、系统安全加固 1.账号安全基本措施 1.1系统账号清理 1.1.1延伸 1.2密码安全控制 1.3命令历史限制 1.4终端自动注销 二、使用su命令切换用户 1.用途及用法 2.密码验证 3.限制使用su命令的用户 4.查看su操作记录 5.sudo&#xff08;superuse do&#xff09;…

Linux下QT生成的(.o)、(.a)、(.so)、(.so.1)、(.so.1.0)、(.so.1.0.0)之间的区别

记录一下遇到的问题&#xff1a;Linux系统下Qt编译第三方动态库会生成多个.so文件&#xff0c;不了解的小伙伴可能很疑惑&#xff1a; &#xff08;1&#xff09;Linux 下 QT 生成的&#xff08;.o&#xff09;、&#xff08;.a&#xff09;和&#xff08;.so&#xff09;三个文…

如何向嵌入式设备中添加tcpdump工具

说明&#xff1a;tcpdump是一个在网络设备调试中一个非常重要的工具&#xff0c;它并不像hexdump等工具集成在busybox里面&#xff0c;也不像其他的软件一样只需要依赖linux标准的库就可以实现&#xff0c;它需要pcap相关的库和加密的相关库。 本文主要是基于realtek 83系列的…

APPnium 自动化实践 :第一步adb 连接手机

1. 下载安装 adb ,添加到环境变量。 ADB Download - Get the latest version of ADB and fastboot 2. 手机开启开发者模式 https://developer.huawei.com/consumer/cn/doc/quickApp-Guides/quickapp-open-developer-option-0000001137005543 3. adb 连接设备 【And…

网络安全与IP地址:构建数字世界的前沿堡垒

网络安全是当今数字社会中不可忽视的挑战之一。而IP地址&#xff0c;作为互联网通信的基础协议&#xff0c;既是数字化时代的桥梁&#xff0c;也是网络安全的关键节点。本文将剖析IP地址在网络安全领域的作用&#xff0c;以及如何利用其特性建立有效的网络安全策略。 IP地址&a…

【图神经网络导论】之第9章模型变体(刘知远)

第9章不同图类型的模型变体 文章目录 第9章不同图类型的模型变体9.1 有向图9.2 异构图9.3 带有边信息的图9.4 动态图9.5 多维图 第4章介绍的基础GNN模型"被用于处理无向图&#xff0c;这些图包含具有标签的节点&#xff0c;是最简单的图。然而&#xff0c;在现实世界中还有…

了解一下InternLM3

在 InternStudio 平台中选择 A100(1/4) 的配置&#xff0c;如下图所示镜像选择 Cuda11.7-conda&#xff0c;接下来打开刚刚租用服务器的进入开发机&#xff0c;并且打开其中的终端开始环境配置、模型下载和运行 demo。入开发机后&#xff0c;在页面的左上角可以切换 JupyterLab…

CSS 压重按钮 效果

<template><view class="cont"><div class="container"><div class="pane"><!-- 选项1 --><label class="label" @click="handleOptionClick(0)":style="{ color: selectedOption ==…

GD32 支持IAP的bootloader开发,使用串口通过Ymodem协议传输固件(附代码)

资料下载: https://download.csdn.net/download/vvoennvv/88713921 一、概述 关于IAP的原理和Ymodem协议&#xff0c;本文不做任何论述&#xff0c;本文只论述bootloader如何使用串口通过Ymodem协议接收升级程序并进行IAP升级&#xff0c;以及bootloader和主程序两个工程的配置…

shell编程学习(二)

变量的类型 预定义变量 $$ 当前进程PID $? 命令执行后的返回状态.0 为执行正确&#xff0c;非 0 为执行错误 $# 位置参数的数量 $* 所有位置参数的内容 …

Next.js 第一次接触

因为需要整个漂亮的在线文档&#xff0c;所以接触了next.js&#xff0c;因为对前端js本身不够熟悉&#xff0c;别说对react.js 又不会&#xff0c;时间又不允许深入研究&#xff0c;所以&#xff0c;为了加一个导航菜单&#xff0c;极其痛苦。 有点小bug&#xff0c;不过不影响…

《EnlightenGAN: Deep Light Enhancement withoutPaired Supervision》论文超详细解读(翻译+精读)

前言 最近学习低照度图像增强时读到这篇EnlightenGAN的论文觉得写得很有意思&#xff0c;讲故事的手法也很值得小白写论文时模仿&#xff0c;今天就来带大家读一下~ 目录 前言 ABSTRACT—摘要 翻译 精读 一、INTRODUCTION—简介 翻译 精读 二、RELATED WORKS—相关工…