问题
odoo中的x2many字段,在编辑状态下可以添加删除行,如果想要禁止编辑状态下的添加和删除,在原生状态下是不可以完成的,通常的思路是把x2many字段声明为只读:
1 | <div> |
lots_info是个one2many类型的字段,其值是通过计算赋值的,但这样做存在下面几个问题:
- 虽然lots_info的tree视图只读了,但是单击某一行依旧有弹窗弹出,而且带有保存并关闭、保存并新建等按钮。
- 只读字段不能缓存,单击保存并关闭后,再次打开该列,并没有上次的信息。
- 只读字段不会保存到数据库中。
解决办法
问题出现了,那么我就需要找到适当的解决办法来解决这个问题,毕竟,这个需求的场景是存在并且有一定的合理性。
目前我们知道,对于添加了readonly属性的字段并不会被存储到数据库当中,即便store=True。这个过程不是在后端代码中进行的,而是在前端js触发保存的那一刻就舍弃了带有readonly的字段。因此,我们需要找到一种途径来确保即便字段声明了readonly也能够被存储起来。第二个问题,对于单击弹窗的问题,我们需要阻断这个弹窗的操作,让它在我们需要的条件下不进行弹窗。
经过长时间的探索,没有发现一种好的方法能够让odoo保存带有readonly属性的字段,退而求其次的,我在context中添加了一个属性x2m_readonly,只要发现字段的context中包含这个属性,就禁用掉前端的create和delete action。至于编辑,阻止掉弹窗就自然而然不能编辑了。
这段逻辑的开发完全基于js,不涉及掉后端python代码。这里简要介绍一下基本思路和关键代码。
首先要明确,我们常见的One2many是odoo qweb框架的一个部件(widget),被定义为One2manyField,One2manyField和Many2manyField同是X2manyField的子类。这些都定义在RelatedField部件中。One2many部件根据当前的编辑模式(编辑、只读)会有两种不同的模式:edit和readonly,对应于我们是否打开编辑按钮的操作。
在readonly模式下
我们单击One2many部件中某一行的动作会打开一个叫做FormViewDialog的部件,这个部件继承自ViewDialog。
FormViewDialog有一个动作叫open,这个就是我们单击x2many部件某一行弹窗的动作,因此,我们要重载这个方法:
1 | FormViewDialog.include({ |
检测这个部件的context中是否包含x2m_readonly属性,不包含的我们才继续调用父类方法,完成弹窗的动作,否则直接忽略掉该动作,表现为”只读”。
在edit模式下
同样的,对于One2many编辑模式下的单击,它会触发One2many部件的私有方法_onEditLine,我们也要予以阻断:
1 | One2manyField.include({ |
接下来要处理的是编辑模式下的Add new line和delete按钮,这个需要在部件显示的时候将其”击毙”,部件显示的方法为_render:
1 | _render: function () { |
这样就基本解决了我们开始所碰见的问题。
最后,需要源代码的同志戳这里