如何在 Odoo 19 中为自定义模块添加章节和备注

如何在 Odoo 19 中为自定义模块添加章节和备注

在 Odoo 中,One2many 字段支持添加章节(Section) 和备注(Note),这两类元素可帮助用户将相关记录分组到有意义的类别中,其中备注还能用于在特定记录的上下文中补充额外信息或说明。例如,在销售订单行中,用户可通过章节和备注更好地组织与管理商品条目。

本文将介绍如何在自定义模型中添加章节和备注功能。操作流程将从创建新模型并添加 One2many 字段开始,逐步完成配置。

一、创建核心模型(Python 代码)

首先需定义两个关联模型:warranty.request(保修申请主模型)和 warranty.request.line(保修申请明细行模型,用于承载章节、备注及商品信息)。

1. 保修申请主模型(warranty.request)

该模型存储保修申请的核心信息(如客户、日期、状态等),并通过 One2many 字段关联明细行。

fromodooimportmodels,fields,_fromdatetimeimportdatetimeclassWarrantyRequest(models.Model):_name='warranty.request'# 模型名称:保修申请_description='Warranty Request'# 模型描述:保修申请_inherit=['mail.thread','mail.activity.mixin']# 继承消息跟踪、活动混合类(支持消息通知)partner_id=fields.Many2one('res.partner',string='客户')# 关联客户模型date=fields.Date(string='申请日期',default=datetime.today())# 申请日期,默认当前日期name=fields.Char(string="序列号",readonly=True,required=True,copy=False,default=_('New'))# 默认值为“New”,后续可通过序列自动生成state=fields.Selection([('draft','草稿'),('to_approve','待审批'),('approved','已审批'),('cancelled','已取消')],string='状态',default='draft',clickable=True)# 状态字段可点击切换warranty_period=fields.Selection([('3months','3 个月'),('6month','6 个月'),('1year','1 年')],string='保修期限',default='3months')warranty_expire_date=fields.Date(string="保修到期日")# 保修到期日期warranty_line_ids=fields.One2many('warranty.request.line',# 关联的明细行模型'warranty_id'# 明细行中关联主模型的字段)description=fields.Html(string='申请说明')# 富文本格式的申请说明

2.保修申请明细行模型(warranty.request.line)

该模型是实现 “章节 / 备注” 功能的核心,需包含 display_type 字段(用于区分 “章节”“备注” 或 “普通商品行”),并通过业务逻辑和 SQL 约束确保数据合法性。

fromodooimport_,api,fields,modelsfromodoo.exceptionsimportUserErrorclassWarrantyRequestLine(models.Model):_name="warranty.request.line"# 模型名称:保修申请明细行_order='warranty_id, sequence, id'# 排序规则:先按主模型ID,再按序号,最后按明细行ID# SQL约束:确保数据完整性_sql_constraints=[# 约束1:需核算行(普通商品行)必须填写必填字段('accountable_required_fields',"CHECK(display_type IS NOT NULL OR (product_id IS NOT NULL AND product_uom_qty IS NOT NULL))","需核算的保修申请明细行缺少必填字段(商品或数量)。"),# 约束2:非核算行(章节/备注)禁止填写商品和数量('non_accountable_null_fields',"CHECK(display_type IS NULL OR (product_id IS NULL AND product_uom_qty = 0))","非核算的保修申请明细行(章节/备注)禁止填写商品或数量。"),]warranty_id=fields.Many2one('warranty.request')# 关联保修申请主模型(反向关联字段)sequence=fields.Integer(string="序号",help="显示保修申请明细行列表时的排序序号",default=10)# 默认序号为10product_id=fields.Many2one('product.product',check_company=True)# 检查商品所属公司与当前环境公司一致name=fields.Text(string="描述",translate=True)# translate=True:支持多语言翻译product_uom_id=fields.Many2one('uom.uom','计量单位',compute='_compute_product_uom_id',store=True,readonly=False,precompute=True)# precompute=True:预计算(提升性能)product_uom_qty=fields.Float(string='数量',required=True,digits='Product Unit of Measure',# 采用商品计量单位的精度配置default=1)display_type=fields.Selection([('line_section',"章节"),('line_note',"备注")],default=False)# 默认无类型(即普通商品行)# 计算字段逻辑:根据商品自动获取计量单位@api.depends('product_id')def_compute_product_uom_id(self):forlineinself:line.product_uom_id=line.product_id.uom_id# 重写创建方法:确保章节/备注行不包含商品和数量信息@api.model_create_multidefcreate(self,vals_list):forvalsinvals_list:# 若当前行是章节/备注(display_type有值)ifvals.get('display_type',self.default_get(['display_type'])['display_type']):# 强制清空商品、数量、计量单位字段vals.update(product_id=False,product_uom_qty=0,product_uom_id=False)returnsuper().create(vals_list)# 重写写入方法:禁止修改行类型(章节/备注/普通行之间不可切换)defwrite(self,values):# 若修改了display_type,且存在行的原类型与新类型不一致if'display_type'invaluesandself.filtered(lambdaline:line.display_type!=values.get('display_type')):raiseUserError(_("无法修改保修申请明细行的类型。请删除当前行,重新创建对应类型的行。"))returnsuper().write(values)

二、配置视图(XML 代码)

需通过 XML 定义主模型的表单视图,重点为 One2many 字段(warranty_line_ids)配置章节与备注专用组件(section_and_note_one2many 组件),并添加 “添加产品”“添加章节”“添加备注” 的快捷按钮。

<recordid="warranty_request_form_view"model="ir.ui.view"><fieldname="name">warranty.request.form.view</field><!-- 视图名称 --><fieldname="model">warranty.request</field><!-- 关联的主模型 --><fieldname="arch"type="xml"><form><!-- 表单视图根标签 --><sheet><!-- 表单“工作表”区域(Odoo 标准布局) --><!-- 顶部基础信息分组 --><group><group><fieldname='partner_id'required="True"string="客户"/></group><group><fieldname='date'string="申请日期"/><fieldname='warranty_period'string="保修期限"/><fieldname='warranty_expire_date'string="保修到期日"/></group></group><!-- 标签页区域 --><notebook><!-- 标签1:商品明细(承载章节/备注/商品行) --><pageid="product_page"name="商品明细"><!-- One2many字段:配置章节与备注组件 --><fieldname="warranty_line_ids"widget="section_and_note_one2many"><!-- 明细行列表视图(可编辑,新增行在底部) --><liststring="商品明细行"editable="bottom"><!-- 快捷操作按钮组(添加产品/章节/备注) --><control><createname="add_product_control"string="添加产品"/><!-- 默认创建“章节”行 --><createname="add_section_control"string="添加章节"context="{'default_display_type':'line_section'}"/><!-- 默认创建“备注”行 --><createname="add_note_control"string="添加备注"context="{'default_display_type':'line_note'}"/></control><!-- 隐藏display_type字段(仅用于逻辑判断,不显示给用户) --><fieldname="display_type"column_invisible="True"/><!-- 序号字段(支持拖拽排序) --><fieldname="sequence"widget="handle"/><!-- 商品字段:仅普通行必填(章节/备注行无需填写) --><fieldname="product_id"required="not display_type"string="产品"/><!-- 描述字段(章节/备注的标题/内容,普通行的商品描述) --><fieldname="name"/><!-- 数量字段:仅普通行必填 --><fieldname="product_uom_qty"/><!-- 计量单位字段:仅普通行必填 --><fieldname="product_uom_id"required="not display_type"/></list></field></page><!-- 标签2:申请说明 --><pageid="description_page"name="申请说明"><!-- 富文本说明字段:仅草稿状态可编辑 --><fieldname="description"readonly="state !='draft'"/></page></notebook></sheet><!-- 消息聊天区(支持添加评论、附件等) --><chatter/></form></field></record>

这会产生以下视图:默认情况下,我们会得到“添加行”控制按钮。

三、实现章节与备注的关键步骤

若需在自定义 One2many 模型中支持章节与备注,需严格遵循以下 4 个步骤。

步骤 1:在明细行模型中添加 display_type 字段

在 One2many 关联的明细行模型(如 warranty.request.line)中,必须添加 display_type 选择字段,用于区分行类型(章节 / 备注 / 普通行);同时需添加 name 字段,用于存储章节标题或备注内容:

display_type=fields.Selection([('line_section',"章节"),('line_note',"备注")],default=False)name=fields.Text(string="描述",translate=True)

步骤 2:重写 create 和 write 方法

@api.model_create_multidefcreate(self,vals_list):forvalsinvals_list:ifvals.get('display_type',self.default_get(['display_type'])['display_type']):vals.update(product_id=False,product_uom_qty=0,product_uom_id=False)returnsuper().create(vals_list)

·create 方法:确保创建章节 / 备注行时,自动清空商品(product_id)、数量(product_uom_qty)等核算字段,避免数据冲突。

defwrite(self,values):if'display_type'invaluesandself.filtered(lambdaline:line.display_type!=values.get('display_type')):raiseUserError(_("无法修改保修申请明细行的类型。请删除当前行,重新创建对应类型的行。"))returnsuper().write(values)

·write 方法:禁止修改行类型(如 “章节” 不可改为 “备注” 或 “普通行”),需删除原行后重新创建,保证数据逻辑一致性。

步骤 3:添加 SQL 约束

通过强制规定保修请求行要么是显示行(设置了 display_type),要么是可核算行(设置了 product_id 和 quantity),但不能同时是两者,从而确保数据完整性。

_sql_constraints=[('accountable_required_fields',"CHECK(display_type IS NOT NULL OR (product_id IS NOT NULL AND product_uom_qty IS NOT NULL))","需核算的保修申请明细行缺少必填字段(商品或数量)。"),('non_accountable_null_fields',"CHECK(display_type IS NULL OR (product_id IS NULL AND product_uom_qty = 0))","非核算的保修申请明细行(章节/备注)禁止填写商品或数量。"),]

·non_accountable_null_fields 约束:保证对于设置了 display_type 的行,product_id 必须为空,并且数量必须为零。
·non_accountable_null_fields 约束:确保当设置了 display_type 时,product_id 必须保持为空,并且数量必须设置为零。

步骤 4:在视图中配置组件与控制按钮

1、配置专用组件:为 One2many 字段添加 widget=“section_and_note_one2many”,启用章节与备注的可视化样式(如章节标题加粗、备注行斜体)。

<fieldname="warranty_line_ids"widget="section_and_note_one2many">

2、添加快捷按钮:在 标签内通过 定义 “添加产品”“添加章节”“添加备注” 按钮,并通过 context 预设 display_type 值,实现点击即创建对应类型的行。
这些控件使用户能够快速添加具有为章节和备注预置上下文的新记录。

<control><createname="add_product_control"string="添加产品"/><!-- 默认创建“章节”行 --><createname="add_section_control"string="添加章节"context="{'default_display_type':'line_section'}"/><!-- 默认创建“备注”行 --><createname="add_note_control"string="添加备注"context="{'default_display_type':'line_note'}"/></control>

·产品控件:没有任何特定上下文,这将生成标准的产品行。
·章节控件:默认将 display_type 设置为 “line_section”。
·备注控件:默认将 display_type 设置为 “line_note”。

3、隐藏 display_type 字段:通过 column_invisible=“True” 隐藏该字段,避免用户误操作。

<fieldname="display_type"column_invisible="True"/>

4、动态设置必填规则:为 product_id、product_uom_qty 等字段设置 required=“not display_type”,仅普通行强制必填。

<fieldname="name"/><fieldname="product_uom_qty"/><fieldname="product_uom_id"required="not display_type"/>

确保 product_id 和 quantity 字段仅在未设置 display_type 时为必填。

在 One2many 树形视图中,用户可以添加章节和备注,如下面的截图所示。

四、章节与备注的优势

在 Odoo 中,在 One2Many 字段中使用章节和备注提供了多种优势,可以增强组织性、用户体验和整体效率。章节允许用户在表单或视图中轻松分离和识别不同的类别或数据集,从而提高信息的可读性。同时,备注提供了一种包含与特定记录直接相关的额外细节或评论的方式。

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

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

相关文章

广告学考研白热化突围:AI证书成上岸关键加分项

广告学考研赛道愈发拥挤&#xff0c;不仅有着63.2%的高复试淘汰率&#xff0c;跨考生占比更超六成&#xff0c;传统备考已难破“高分难上岸”困局。在此背景下&#xff0c;一张高价值AI证书&#xff0c;成为广告学考生打破同质化竞争、精准突围的核心抓手。如今广告学已升级为融…

如何在 Odoo 19 中创建日历视图

如何在 Odoo 19 中创建日历视图 在 Odoo 19 中&#xff0c;日历视图是管理和可视化基于时间数据的强大界面&#xff0c;常用于约会、截止日期、任务、会议等日程安排场景。它提供了直观的图形化布局&#xff0c;可按日、周、月展示记录&#xff0c;在项目、销售、CRM 等模块中尤…

Java毕设项目推荐-基于springboot的旅行指南行程规划、景点推荐系统的设计与实现【附源码+文档,调试定制服务】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

【计算机毕业设计案例】基于springboot的旅行指南个性化行程推荐系统的设计与实现(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

科大讯飞秋招笔试真题 - 字符拼接 字典序最小的字符串拼接 圆心覆盖

字符拼接 题目描述 给定两个由可见字符和空格组成的字符串s和t&#xff0c;其中字符串t的长度为偶数. 请将t的后半部分嫁按到s的未尾&#xff0c;并输出嫁接后的s以及t 的前半部分。 本题字符串的字符集为 ASCIl 码在 32 到 126 之间的字符&#xff0c;即大小写字母、数字、标点…

基于SpringBoot的KPL赛事综合管理系统的设计与实现

KPL赛事综合管理系统课题背景 电子竞技产业近年来发展迅猛&#xff0c;尤其是移动电竞领域&#xff0c;王者荣耀职业联赛&#xff08;KPL&#xff09;作为国内顶级移动电竞赛事&#xff0c;其规模与影响力持续扩大。随着赛事体系日趋复杂&#xff0c;传统人工管理模式已难以应对…

新闻学学生留学信息差避坑指南:掌握这些,学习留学两不误

新闻学留学的核心竞争力在于把控信息差&#xff0c;其受地域媒体环境、行业认证等因素影响极深&#xff0c;易陷入高投入低回报困境。本文从选校、申请、学业、就业四大环节&#xff0c;拆解核心陷阱&#xff0c;助力平衡学术与职业发展。一、选校避坑&#xff1a;跳出排名&…

基于python的搜索引擎设计与实现

搜索引擎设计与实现的课题背景 在当今信息爆炸的时代&#xff0c;搜索引擎已成为人们获取信息的重要工具。随着互联网数据的快速增长&#xff0c;如何高效地检索、排序和呈现信息成为计算机科学领域的重要研究方向。Python作为一种高效、灵活的编程语言&#xff0c;因其丰富的库…

基于SpringBoot的车辆违章信息管理系统的设计与实现

车辆违章信息管理系统的背景与意义 随着城市化进程加快和机动车保有量激增&#xff0c;交通违章现象日益频发&#xff0c;传统人工管理模式在数据处理效率、信息共享和执法透明度等方面面临严峻挑战。据公安部统计&#xff0c;2022年全国机动车保有量达4.17亿辆&#xff0c;同比…

基于Bilibili青少年模式使用情况的数据分析系统设计与实现开题报告

基于Bilibili青少年模式使用情况的数据分析系统设计与实现开题报告 一、研究背景与意义 &#xff08;一&#xff09;研究背景 随着数字技术的深度渗透&#xff0c;青少年已成为互联网消费的核心群体。截至2025年&#xff0c;我国青少年网民规模突破2.8亿&#xff0c;日均上网时…

《把脉行业与技术趋势》-59-《如何快速了解一个行业》哪些人需要如何快速了解一个行业?

《如何快速了解一个行业》是一本极具实战价值的方法论指南&#xff0c;适用于多种人群。不同角色因目标不同&#xff0c;对“快速了解”的需求和侧重点也各不相同。一、哪些人需要“快速了解一个行业”&#xff1f;人群典型场景核心诉求1. 投资者&#xff08;VC/PE/股票投资者&…

基于Hadoop的南昌市房价预测系统的设计与实现开题报告

基于Hadoop的南昌市房价预测系统的设计与实现开题报告 一、研究背景与意义 &#xff08;一&#xff09;研究背景 随着我国房地产市场的持续发展与调控政策的不断深化&#xff0c;房价走势已成为关乎民生福祉、经济稳定与城市发展的核心议题。南昌市作为江西省省会&#xff0c;近…

12.平铺视图、窗口、消息框部件(lv_tileview,lv_win,lv_msgbox)

12.平铺视图、窗口、消息框部件(lv_tileview,lv_win,lv_msgbox)Hello World

【C语言】详解C语言字节打包:运算符优先级、按位或与字节序那些坑

详解C语言字节打包&#xff1a;运算符优先级、按位或与字节序那些坑 在嵌入式开发、网络编程中&#xff0c;字节打包&#xff08;将多个单字节数据拼接为多字节数据&#xff09;是高频操作&#xff0c;而新手很容易在运算符使用、优先级判断上踩坑。本文将以一段实际的C语言字节…

我终于狠下心改变家里的网络架构!原来是我高估了自己

从去年2025年末的时候&#xff0c;小白就一直想着把自己辛苦搭建的ESXI虚拟层关闭&#xff0c;改为家用路由器拨号的模式&#xff0c;但是一直迟迟没有动手。 果然&#xff0c;人一旦进入了舒适区&#xff0c;就很难走出来。网络部署一旦稳定使用&#xff0c;就算是想到有能优…

基于数据挖掘的电商用户行为分析系统设计与实现开题报告

基于数据挖掘的电商用户行为分析系统设计与实现开题报告 一、研究背景与意义 &#xff08;一&#xff09;研究背景 在数字经济高速发展的浪潮下&#xff0c;我国电商行业已进入存量竞争时代&#xff0c;用户精细化运营成为企业核心竞争力。截至2025年&#xff0c;我国电商交易总…

什么是信息学奥数(NOI)?

“信息学奥数”通常是指信息学奥林匹克竞赛&#xff0c;全称为全国青少年信息学奥林匹克竞赛&#xff08;NOI&#xff0c;National Olympiad in Informatics&#xff09;&#xff0c;是中国面向中学生的一项高水平计算机科学竞赛活动。它属于五大学科奥林匹克竞赛之一&#xff…

AD域控批量配置域用户下次登录需要修改密码

##### 读取csv文件批量设置域用户下次登录需要修改密码Import-Module ActiveDirectory# 配置参数(SamAccountName参数为用户账号所在的列) $CSVFile = "C:\temp\All_AD_Users.csv" $UsernameColumn = "…

2026.1.14总结

今天主要完成python基础语法的学习,大致过了一遍Python 基础语法 1.1 变量、数据类型、运算符变量与数据类型 name = "Python学习" # 字符串 age = 3 # 整数 height = 1.75 # 浮点数 …

Stable Diffusion Web UI 绘世版 v4.6.1 整合包:一键极速部署,深度解决 AI 绘画环境配置与 CUDA 依赖难题

对于从事 AI 创作或 AIGC 研究的开发者来说&#xff0c;Stable Diffusion (SD) 是目前本地化部署的首选框架。然而&#xff0c;原生环境搭建往往涉及复杂的 Python 虚拟环境管理、CUDA 版本的严格匹配以及大量的 Git 依赖拉取&#xff0c;任何一个环节出错都可能导致部署失败。…