暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

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

751





Odoo

神州数码云基地

在 Odoo 上的尝试、调研与分享




本期内容 

 如何创建和删除表单明细 



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


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


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


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


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


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




表单明细的创建与删除  


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


首先,在后端使用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          #给关联字段赋值


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




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


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


    明细表虽是表数据,但是在主模型里,依然是一个一对多的字段,只要是字段就能使用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中灵活实现表单功能的思路。


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






      关于在Odoo中创建和删除

      明细表单的分享就到这儿啦~


      如果你有更好的办法或疑问

      欢迎加入社群一起讨论哦⬇

      本期作者 

      张备 



      更多精彩内容 





      了解云基地,就现在!


      IT技术哪家

      神州数码最在行

      行业新星后起之秀

      历史虽不长,但实 力 强




      文章转载自神州数码云基地,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论