新闻中心
Odoo 16:在表单视图中动态修改Tree视图属性的教程

本教程详细介绍了如何在odoo 16的表单视图中,根据当前记录的数据动态修改内嵌tree视图的属性,例如设置分页限制。文章深入探讨了通过重写`get_view`方法并利用`self.env.context['params'].get('id')`准确获取当前记录id的关键技术,并提供了完整的代码示例和实现步骤,帮助开发者实现高度定制化的视图行为。
引言:动态视图定制的需求
Odoo提供了一套强大的视图系统,允许开发者通过XML定义界面的结构和行为。然而,在某些业务场景下,我们可能需要根据当前正在查看或编辑的记录的具体数据,动态地调整视图中某个组件的属性。一个常见的例子是在主表单中嵌入一个子Tree视图(也称为One2Many或Many2Many字段的列表视图),并希望根据主记录的某个字段值来改变这个子Tree视图的分页限制、可编辑性或列的显示。
本文将以在Odoo 16的stock.picking(调拨单)表单视图中,根据调拨单记录上定义的limit字段值,动态设置其关联的move_ids_without_package Tree视图(调拨行)的分页限制为例,详细讲解如何实现这一需求。
核心机制:重写 get_view 方法
Odoo在加载任何视图时,都会调用相应的模型上的get_view方法。这个方法是进行视图XML架构动态修改的理想入口点。通过重写此方法,我们可以在视图数据发送到前端渲染之前,对其XML结构进行解析、修改和重新序列化。
get_view方法接收以下主要参数:
- view_id: 视图的数据库ID。
- view_type: 视图的类型(如'form', 'tree', 'kanban'等)。
- options: 包含额外上下文信息的字典。
准确获取当前记录ID
在get_view方法中,一个常见的挑战是准确获取当前正在加载的表单视图所对应的记录ID。开发者有时会尝试使用self.env.context.get('active_id'),但在get_view的上下文中,active_id可能不总是指向当前表单的记录,尤其是在通过菜单项或关联字段打开表单时。
Motiff妙多
Motiff妙多是一款AI驱动的界面设计工具,定位为“AI时代设计工具”
334
查看详情
正确的做法是利用self.env.context['params'].get('id')。 params字典通常包含更精确的视图加载参数,其中id键会可靠地提供当前正在加载的表单视图所关联的记录的数据库ID。
实现动态Tree视图属性修改
下面我们将通过一个完整的代码示例,演示如何在stock.picking模型中实现根据记录的limit字段动态设置move_ids_without_package Tree视图的分页限制。
首先,我们需要在stock.picking模型中添加一个用于存储分页限制的字段,并重写get_view方法。
from odoo import models, fields, api
from lxml import etree
import logging
_logger = logging.getLogger(__name__)
class StockPicking(models.Model):
_inherit = "stock.picking"
limit = fields.Integer(string="Tree 分页限制", default=0, help="设置关联Tree视图的每页显示记录数。0表示不设置限制。")
def tree_pagination_limit_apply(self):
"""
一个示例方法,可以在用户界面中调用,以触发当前视图的重新加载,
从而应用get_view中定义的动态修改。
例如,可以在表单上添加一个按钮,点击后调用此方法。
&quo
t;""
return {
'type': 'ir.actions.client',
'tag': 'reload',
}
@api.model
def get_view(self, view_id=None, view_type='form', **options):
_logger.info(f"Custom get_view for StockPicking called for view_type: {view_type}")
# 1. 调用父类方法获取原始视图架构
# 这是非常重要的一步,确保Odoo的默认视图处理逻辑不被破坏
result = super(StockPicking, self).get_view(view_id=view_id, view_type=view_type, **options)
# 2. 仅在表单视图类型下进行修改,避免影响其他视图类型
if view_type == 'form':
# 3. 解析视图XML架构
# 使用lxml库解析XML字符串,便于操作
doc = etree.XML(result['arch'])
# 4. 获取当前表单记录的ID
# 关键:从self.env.context['params']中获取id,这是获取当前表单记录ID最可靠的方式
active_id = self.env.context['params'].get('id') if 'params' in self.env.context else None
if active_id:
try:
# 5. 浏览当前记录以获取其数据
current_record = self.browse(active_id)
# 检查记录是否存在且limit字段值大于0才进行设置
if current_record and current_record.limit > 0:
# 6. 定位目标Tree视图并修改属性
# 使用XPath表达式精确查找名为'move_ids_without_package'的field下的'tree'标签
for tree_node in doc.xpath("//field[@name='move_ids_without_package']/tree"):
tree_node.set('limit', str(current_record.limit))
_logger.info(f"为记录ID {active_id} (Picking Name: {current_record.name}) 设置Tree视图限制为 {current_record.limit}")
break # 假设一个field下只有一个tree,找到后即可退出循环
except Exception as e:
_logger.error(f"在设置Tree视图限制时发生错误 (记录ID: {active_id}): {e}")
# 7. 将修改后的XML架构更新回结果中
# lxml的tostring方法返回bytes,需要解码为unicode字符串
result['arch'] = etree.tostring(doc, encoding='unicode').decode('utf-8')
return result
代码解析与注意事项
- _inherit = "stock.picking": 继承stock.picking模型以添加新字段和重写方法。
- limit = fields.Integer(...): 定义一个整数字段limit,用于在每个调拨单记录上存储自定义的分页限制。default=0表示默认不设置限制。
- tree_pagination_limit_apply(self): 这是一个辅助方法,可以绑定到表单上的按钮。当用户点击该按钮时,它会触发客户端的reload动作,强制Odoo重新加载当前视图,从而使get_view中的修改生效。
- @api.model: get_view方法必须使用@api.model装饰器,因为它是一个类方法,不依赖于特定的记录集。
- result = super(StockPicking, self).get_view(...): 这是至关重要的一步。 始终先调用父类的get_view方法,以获取Odoo标准处理后的原始视图架构。在此基础上进行修改,可以避免破坏Odoo的默认视图逻辑。
- if view_type == 'form':: 限制修改仅在表单视图类型下进行。在其他视图类型(如列表视图、看板视图)下,Tree视图的结构和上下文可能不同,不应进行相同的修改。
- doc = etree.XML(result['arch']): 使用lxml库将视图的XML架构字符串解析为一个可操作的XML树对象。lxml是一个高性能的XML处理库,非常适合此类任务。
- active_id = self.env.context['params'].get('id'): 这是本教程的核心修复点。它确保我们获取到的是当前正在打开的表单记录的正确ID。
- current_record = self.browse(active_id): 通过获取到的active_id,浏览(browse)到对应的记录,以便访问其字段值(例如current_record.limit)。
-
doc.xpath("//field[@name='move_ids_without_package']/tree"): 使用XPath表达式来定位目标Tree视图。
- //field[@name='move_ids_without_package']:查找整个XML文档中所有名为move_ids_without_package的
标签。 - /tree:在其子节点中查找
标签。 - lxml的xpath方法返回一个匹配元素的列表。
- //field[@name='move_ids_without_package']:查找整个XML文档中所有名为move_ids_without_package的
- tree_node.set('limit', str(current_record.limit)): 找到目标Tree节点后,使用set()方法修改其limit属性。注意,属性值必须是字符串。
- result['arch'] = etree.tostring(doc, encoding='unicode').decode('utf-8'): 将修改后的XML树重新序列化回字符串,并更新到result['arch']中。etree.tostring默认返回字节串,需要使用decode('utf-8')将其转换为Python字符串。
- 错误处理: 包含try-except块是良好的编程实践,可以捕获在XML解析、记录浏览或属性设置过程中可能发生的错误,防止整个系统崩溃,并记录详细日志以便调试。
- 性能考量: get_view方法在每次视图加载时都会执行。频繁的XML解析和序列化可能会带来一定的性能开销。因此,建议仅在确实需要动态修改视图时才使用此方法,并尽量优化XPath表达式和逻辑,减少不必要的处理。
总结
通过重写Odoo模型的get_view方法,并结合lxml库进行XML架构操作,我们可以实现高度灵活和动态的视图定制。关键在于理解get_view的执行时机,以及如何通过self.env.context['params'].get('id')可靠地获取当前表单记录的ID。掌握这些技术,开发者可以根据业务需求,创建更加智能和用户友好的Odoo界面。在实际应用中,务必注意代码的健壮性、性能影响以及与Odoo未来版本的兼容性。
以上就是Odoo 16:在表单视图中动态修改Tree视图属性的教程的详细内容,更多请关注其它相关文章!
# 转换为
# 运城seo优化规划
# 文体类项目关键词排名
# 宜昌网站建设和推广怎样
# 北京关键词seo
# 拼多多查关键词排名网页
# 公司网站优化商丘
# 江苏顶级媒体营销推广
# 沈阳seo优化培训
# 阿虎seo
# 网站推广营销模板怎么写
# 数据包
# 序列化
# 是在
# python
# 是一个
# 加载
# 这是
# 重写
# 分页
# 表单
# 字符串解析
# xml处理
# xml解析
# 字节
# app
# node
# 前端
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
深入理解J*aScript Promise异步执行与微任务队列
J*aScript中针对特定容器内图片动画的实现教程
Win11怎么修改默认浏览器_Windows 11设置Chrome为默认
Win11怎么关闭快速启动_Win11彻底关机设置教程
PHP 枚举:根据字符串获取枚举案例的策略与实现
win11如何卸载Windows更新补丁 Win11解决更新导致系统不稳定的问题【修复】
J*a递归快速排序中静态变量的状态管理与陷阱
Fabric模组开发:自定义物品与物品组的现代管理方法
QQ邮箱在线登录平台 QQ邮箱个人邮箱网页版入口
Win11怎么隐藏桌面图标 Win11一键隐藏所有桌面元素及恢复显示
夸克浏览器桌面版同步不了书签怎么处理 夸克浏览器跨设备同步异常解决方案
抖音网页版快捷访问 抖音网页版网页版入口操作教程
c++如何实现单例设计模式_c++线程安全的单例模式写法
内存疯狂猛猛涨价:主板销量直接腰斩!
4399网页游戏电脑版全新入口 4399电脑端在线玩指南
可靠CSGO开箱平台解析 CSGO开箱网合集
新手怎么开始学化妆 零基础化妆入门教程
sublime侧边栏怎么增强功能_SideBarEnhancements for sublime安装与配置
百度网盘网页版入口 百度网盘网页版官方登录网址
顺丰快递查单号物流信息 顺丰快递小程序查询入口
QQ邮箱网页版邮箱入口 QQ邮箱官方登录平台
Win10桌面图标出现小盾牌怎么办 Win10去除UAC图标教程【解决】
在J*a中如何在J*a中使用异常机制记录错误日志_异常日志实践经验
sublime如何配置Go语言开发环境_sublime搭建Golang编译运行系统
mcjs网页版在线存档 mcjs云存档登录入口
今日头条怎么同步内容到抖音_今日头条内容同步到抖音教程
C++如何生成随机数_C++ random库使用方法与范围设置
C++编译期如何执行复杂计算_C++模板元编程(TMP)技巧与应用
中兴BladeV30怎样用测距估书架层高_iPhone中兴BladeV30测距估书架层高【家装参考】
Python异步编程实践:使用Binance API构建实时交易数据流
深入理解Go语言中Map值与方法接收器的交互:为什么需要临时变量
Win10如何恢复误删的快捷方式_Win10重建常用软件快捷方式
CKEditor 5 自定义构建在React应用中渲染失败的调试与解决
菜鸟取件码是什么怎么查 最全查询渠道汇总
QQ邮箱官方邮箱登录入口 QQ邮箱网页版快速访问
J*aScript中赋值与自增运算符的复杂交互与执行机制
Node.js 中使用 node-cron 实现定时 API 数据抓取与处理
处理Kafka消费者会话超时:深入理解消息处理语义与幂等性
使用Pandas转换并合并DataFrame:多列映射至统一结构
Yandex免登录官网入口_俄罗斯Yandex搜索引擎直达链接
在Go语言中利用后缀数组处理多字符串:实现高效文本匹配与自动补全
QQ邮箱在线使用入口 QQ邮箱个人账号网页版登录
地铁跑酷免费秒玩入口链接 地铁跑酷小游戏免费秒玩网站
理解Python模块与全局变量的作用域管理
C++的std::mdspan是什么_C++23中用于操作多维数组的非拥有视图
如何使用 Excel 发布器与 Power BI 分享 Excel 洞察
CSS实现侧边栏导航项全宽圆角悬停背景效果
在Go开发中优雅管理ListenAndServe进程:GoSublime集成方案
知乎APP怎么管理已购盐选内容_知乎APP盐选内容购买记录与查看方法
age动漫网站入口 age动漫官网直接访问入口


2025-11-27
浏览次数:次
返回列表
t;""
return {
'type': 'ir.actions.client',
'tag': 'reload',
}
@api.model
def get_view(self, view_id=None, view_type='form', **options):
_logger.info(f"Custom get_view for StockPicking called for view_type: {view_type}")
# 1. 调用父类方法获取原始视图架构
# 这是非常重要的一步,确保Odoo的默认视图处理逻辑不被破坏
result = super(StockPicking, self).get_view(view_id=view_id, view_type=view_type, **options)
# 2. 仅在表单视图类型下进行修改,避免影响其他视图类型
if view_type == 'form':
# 3. 解析视图XML架构
# 使用lxml库解析XML字符串,便于操作
doc = etree.XML(result['arch'])
# 4. 获取当前表单记录的ID
# 关键:从self.env.context['params']中获取id,这是获取当前表单记录ID最可靠的方式
active_id = self.env.context['params'].get('id') if 'params' in self.env.context else None
if active_id:
try:
# 5. 浏览当前记录以获取其数据
current_record = self.browse(active_id)
# 检查记录是否存在且limit字段值大于0才进行设置
if current_record and current_record.limit > 0:
# 6. 定位目标Tree视图并修改属性
# 使用XPath表达式精确查找名为'move_ids_without_package'的field下的'tree'标签
for tree_node in doc.xpath("//field[@name='move_ids_without_package']/tree"):
tree_node.set('limit', str(current_record.limit))
_logger.info(f"为记录ID {active_id} (Picking Name: {current_record.name}) 设置Tree视图限制为 {current_record.limit}")
break # 假设一个field下只有一个tree,找到后即可退出循环
except Exception as e:
_logger.error(f"在设置Tree视图限制时发生错误 (记录ID: {active_id}): {e}")
# 7. 将修改后的XML架构更新回结果中
# lxml的tostring方法返回bytes,需要解码为unicode字符串
result['arch'] = etree.tostring(doc, encoding='unicode').decode('utf-8')
return result