Odoo丨手把手教你灵活控制表单明细的创建与删除!

news2025/2/5 17:49:04

文章目录

  • 一、前言
  • 二、表单明细的创建与删除
    • 1.根据主表字段带出明细信息
    • 2.根据主表字段控制明细表的添加和删除功能
  • 三、总结


一、前言

我们知道,在Odoo页面上,控制的最小单位是字段,可通过Odoo提供的属性,控制字段的必填、只读、隐藏等功能。

但对于form表单下的tree视图,总体来讲仍是一个字段,可通过tree视图的属性create=“1” delete=“1” 来控制明细信息的创建和删除,但不能单独控制具体某一行的属性。

于是,我们引发了以下思考:

能不能在页面上设置一个控制开关,开启时,明细行就能添加和删除,关闭时就不能;

如果能通过开关字段控制明细行属性,能否通过字段带出明细数据,并禁止添加和删除,实现不只是只读,而是可编辑模式?

带着上述疑问,本期我们就一起来看看,如何在Odoo上实现灵活创建和删除表单页明细。


二、表单明细的创建与删除

1.根据主表字段带出明细信息

首先,在后端使用onchange监听能带出明细的字段,确保该字段数据内容正确。同时拿到数据之后,通过模型,查询要带出的数据,对数据进行格式化。

然后根据Odoo默认的关联关系来绑定,就能实现明细的动态创建了。

举个例子,模型test是主表,其中name_rel就是关联字段,通过姓名带出信息:

在这里插入图片描述
那么,具体的后端代码实现可以参考如下:


@api.onchange('name_a')    #监听姓名字段
def _name_a(self):
    args_list = []
    self.name_rel = None #把关联关系接触,每次触发清楚上次的明细
 if self.name_a:
        purchase_detail = [{             #可以通过sql查询,或者接口获取,拿到想要的明细数据
            'name_b': '打篮球', 
 'time_b': '2年'
 }]
        for detail in purchase_detail:
            num = 1
 args = {
                'name_b': detail['name_b'],
 'time_b': detail['time_b'],
 }
            args_list.append((0, 0, args))         #建立odoo规定的关联关系!!
            num += 1
 self.res_sale_product_detail = args_list          #给关联字段赋值

通过以上操作,表单带出问题就顺利解决了⬇

在这里插入图片描述

2.根据主表字段控制明细表的添加和删除功能

如果说带出功能是后端的问题,那么隐藏添加明细和删除就是前端来控制的。

明细表虽是表数据,但是在主模型里,依然是一个一对多的字段,只要是字段就能使用widget控制,我们顺着这条思路进行探索。

在研磨源码之后,我们发现页面每次改动之后,都是会调用前端基础控件FieldX2Many的reset方法;

虽然我们是拓展FieldOne2Many方法,但是FieldOne2Many方法也是拓展于基础模型FieldX2Many的,所以我们可以直接在新方法里重写reset方法。

当然在起初进入页面时,可以修改基础的init属性,保证页面初始加载,或是动态改变之后,依然能生效。

具体操作代码如下:


var hideCreateDelete = FieldOne2Many.extend({
    init: function (parent, name, record, options) {
        this._super.apply(this, arguments);
 let x = record.data['想要控制的字段']; 
 var arch = this.view && this.view.arch;
 if (x) {
            if (arch) {
                this.activeActions.create = false;
 this.activeActions.delete = false;
 this.editable = arch.attrs.editable;
 }
        } else {
            if (arch) {
                this.activeActions.create = true;
 this.activeActions.delete = true;
 this.editable = arch.attrs.editable;
 }
        }
    },
 reset: function (record, ev, fieldChanged) {
        let x = record.data['想要控制的字段'];
 const oldCanCreate = this.canCreate;
 const oldCanDelete = this.canDelete;
 const oldCanLink = this.canLink;
 const oldCanUnlink = this.canUnlink;
 var arch = this.view && this.view.arch;
 if (x) {
            this.activeActions.create = false;
 this.activeActions.delete = false;
 this.editable = arch.attrs.editable;
 } else {
            this.activeActions.create = true;
 this.activeActions.delete = true;
 this.editable = arch.attrs.editable;
 }
        this._computeAvailableActions(record);
 const actionsChanged =
            this.canCreate !== oldCanCreate ||
            this.canDelete !== oldCanDelete ||
            this.canLink !== oldCanLink ||
            this.canUnlink !== oldCanUnlink;

 // If 'fieldChanged' is false, it means that the reset was triggered by
 // the 'resetOnAnyFieldChange' mechanism. If it is the case, if neither
 // the modifiers (so the visible columns) nor the available actions
 // changed, the reset is skipped.
 if (!fieldChanged && !actionsChanged) {
            var newEval = this._evalColumnInvisibleFields();
 if (_.isEqual(this.currentColInvisibleFields, newEval)) {
                this._reset(record, ev); // update the internal state, but do not re-render
 return Promise.resolve();
 }
        } else if (ev && ev.target === this && ev.data.changes && this.view.arch.tag === 'tree') {
            var command = ev.data.changes[this.name];
 // Here, we only consider 'UPDATE' commands with data, which occur
 // with editable list view. In order to keep the current line in
 // edition, we call confirmUpdate which will try to reset the widgets
 // of the line being edited, and rerender the rest of the list.
 // 'UPDATE' commands with no data can be ignored: they occur in
 // one2manys when the record is updated from a dialog and in this
 // case, we can re-render the whole subview.
 if (command && command.operation === 'UPDATE' && command.data) {
                var state = record.data[this.name];
 var fieldNames = state.getFieldNames({viewType: 'list'});
 this._reset(record, ev);
 return this.renderer.confirmUpdate(state, command.id, fieldNames, ev.initialEvent);
 }
        }
        this._reset(record, ev);
 return this._super.apply(this, arguments);
 },
});

想要实现按条件显示添加明细和删除,我们就要从内部理解关联字段的属性。

this.canCreate是可以创建的,同理canDelete就是能够删除的。

最后我们给明细字段绑定上自定义的widget,一起在页面上见证成果:

在这里插入图片描述

通过我们的设置,在编辑模式下,添加明细和删除实现了隐藏。


三、总结

以上就是今天关于在Odoo中灵活实现表单功能的思路。

在日常的操作中,如果遇到明细表单的创建,删除相关的问题,不妨试试上述分享的方法吧。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Cloud 应用 Proxyless Mesh 模式探索与实践

作者:十眠 Service Mesh 简介 Service Mesh 早已不是一个新兴的概念,目前已经有许多关于 Service Mesh 的探索以及实践。 2016 年可以说是 Service Mesh 的元年,Buoyant 公司 CEO William Morgan 率先发布 Linkerd ,成为业界首…

Java中的多线程(上)

作者:~小明学编程 文章专栏:JavaEE 格言:热爱编程的,终将被编程所厚爱。 目录 多线程 什么是线程 为什么需要多线程 进程和线程的区别(面试重点) Java实现多线程 多线程带来的好处 认识Thread类 T…

前端基础_贝塞尔和二次方曲线

贝塞尔和二次方曲线 贝塞尔曲线可以是二次和三次方的形式,常用于绘制复杂而有规律的形状。 绘制贝塞尔曲线主要使用bezierCurveTo方法。该方法可以说是lineTo的曲线版,将从当前坐标点到指定坐标点中间的贝塞尔曲线追加到路径中。该方法的定义如下。 b…

艾美捷耗氧率检测试剂盒说明书及相关研究

细胞内稳态通过ATP的产生来维持。ATP的生成可以通过单独的糖酵解(无氧呼吸)或通过糖酵解与氧化磷酸化的耦合来完成。氧化磷酸化是氧(O2)依赖性的,发生在线粒体中,是哺乳动物细胞合成ATP的最有效和优选的方法…

电力系统可视化——比PowerWorld还精彩(Matlab实现)

目录 1 概述 2 PowerWorld 3 案例及Matlab代码实现 3.1 案例 3. 2 结果展现 3.3 Matlab代码实现 1 概述 信息可视化的应用为电力行业带来了巨大的希望,但其潜力尚未被可视化社区充分挖掘。先前关于电力系统可视化的工作仅限于在地理布局之上描绘原始或处理过的…

【数据结构】单链表OJ

目录 一、反转单链表 描述 二、返回链表的中间节点 三、返回倒数第K个节点 描述 示例1 四、合并两个已排序的链表 描述 五、分隔链表 六、判断一个链表是否为回文结构 描述 示例1 示例2 示例3 七、两个链表的第一个公共结点 描述 输入描述: 返回值描…

LICEcap:GIF屏幕录制工具

写博客的时候,我经常会用到需要自制gif的场景,我之前一直使用视频转gif工具处理https://tool.lu/video2gif/,大致就是利用qq录屏成视频,然后通过工具转成gif。 今天无意间看到其他博主用了 LICEcap 工具 LICEcap 是一款简洁易用的…

“隐形贫困者”自学Python做副业,教你如何月入10000+

现在的年轻人总是觉得攒不下钱,虽然表面风光,每天出入高级CBD,可是几乎每个人都是月光族,这一类人被定义为“隐形贫困者”,原因是什么呢?根据小编的分析,现在人们对生活质量要求普遍提高了&…

毕业设计 单片机智能避障超声波跟随小车 - 物联网 嵌入式

文章目录0 前言1 项目背景2 实现效果3 设计原理HC-SR04超声波模块5 部分代码6 最后0 前言 🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告…

玩转云端 | 数据管理深似海,运维如何变“路人”?

数字技术正在改变人们生产、生活的方方面面。作为数字经济时代的重要生产要素,数据正以指数级别爆发式增长,企业对于数据存储及处理的方式和要求已是“今时不同往日”。最早古人存储数据的方法是“以物记物”或“借物记物”,即用更易于携带的…

如何视频裁剪?建议收藏这几种裁剪视频的方法

现在的网络很是方便,我们可以轻轻松松的在网上找到各种网课视频来进行学习。不过有些网课里面的重点内容不仅比较少,还很分散,让我们很难做到高效的学习。但其实我们可以通过视频裁剪,将有重点内容的视频裁剪下来,这样…

SpringBoot SSMP案例整合二 运维篇

目录 一、程序打包 二、项目打包后 若启动失败 三、虚拟机启动SpringBoot项目(Linux) 四、临时属性 五、配置文件4级分类 六、自定义配置文件 七、多环境开发(yml版本) 八、多环境开发多文件版(yml版&#xf…

C++ Primer 第四章 表达式

C Primer 第四章 表达式4.1. Fundamentals4.1.1. Lvalues and Rvalues4.1.2. Precedence and Associativity4.2. Arithmetic Operators4.4. Assignment Operators4.5. Increment and Decrement Operators4.9. The sizeof Operator4.10. Comma Operator4.11. Type Conversions4.…

中国风?古典系?AI中文绘图创作尝鲜!⛵

💡 作者:韩信子ShowMeAI 📘 深度学习实战系列:https://www.showmeai.tech/tutorials/42 📘 本文地址:https://www.showmeai.tech/article-detail/413 📢 声明:版权所有,转…

Java——B-树

概念 当我们使用avl树或者红黑树进行数据检索时,虽然树是平衡的,可以保证搜索的效率大概是logN。但是当我们的数据量比较大时,只能在内存中存储数据在硬盘中的指针,这时如果我们要检索数据,最少也需要比较树的高度次。…

【算法】单词接龙,合并区间, 二叉搜索树的最近公共祖先,旋转排序数组中的最小值看看有你会的吗?

算法学习有些时候是枯燥的,每天学习一点点 算法题目一. 单词接龙 II 题目描述java 解答参考二. 合并区间 题目描述java 解答参考三. 二叉搜索树的最近公共祖先 题目要求java实现方案四 寻找旋转排序数组中的最小值一. 单词接龙 II 题目描述 按字典 wordList 完成从…

Azure RTOS 嵌入式无线网络框架简化物联网应用开发

一、Azure RTOS概述 Azure RTOS 是一个实时操作系统 (RTOS),适用于由微控制器 (MCU) 提供支持的物联网 (IoT) 和边缘设备, Azure RTOS 旨在支持高度受限设备(电池供电,并且闪存容量不到 64 KB)。简而言之,…

某HR分享:2n和n+3的基数不一样,n+3比2n拿得多!仲裁期间不能入职新公司,千万别轻易仲裁,得不偿失!...

被裁员时,要2n还是要n3?是否选择仲裁?一位hr说,跟走过仲裁的同学和律师朋友打听了下,原来2n和n3完全不一样。n3的n取的是“非私营单位从业人员平均工资”的三倍,杭州市是3.2万。2n的n取的是“全社会就业人员…

Android设计模式详解之单例模式

前言 定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。 使用场景:确保某个类有且仅有一个对象的场景,避免产生多个对象消耗过多的资源。比如要访问IO和数据库资源,应该考虑使用单例模式。 …

JAVA开发(数据库表设计)

对于大型系统数据库设计,需要进行一定的规划和规范,才能方便系统扩展和维护。一般系统的数据库设计要求,有数据库表系统规划,数据库表系统命名规范和设计规范。 一、数据库表系统规划 1、按系统规划或者按微服务规划 2、按业务…