ODOO模块导入数据忽略错误
经常遇到大量的数据导入,不仅耗时很长,如果其中有一条数据有异常产生错误,就会导致整个过程回滚,这是非常悲剧的,其中相关源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
for id, xid, record, info in converted: try: cr.execute('SAVEPOINT model_load_save') except psycopg2.InternalError as e: # broken transaction, exit and hope the source error was # already logged if not any(message['type'] == 'error' for message in messages): messages.append(dict(info, type='error',message=u"Unknown database error: '%s'" % e)) break try: ids.append(ModelData._update(self._name, current_module, record, mode=mode, xml_id=xid, noupdate=noupdate, res_id=id)) cr.execute('RELEASE SAVEPOINT model_load_save') except psycopg2.Warning as e: messages.append(dict(info, type='warning', message=str(e))) cr.execute('ROLLBACK TO SAVEPOINT model_load_save') except psycopg2.Error as e: messages.append(dict(info, type='error', **PGERROR_TO_OE[e.pgcode](self, fg, info, e))) # Failed to write, log to messages, rollback savepoint (to # avoid broken transaction) and keep going cr.execute('ROLLBACK TO SAVEPOINT model_load_save') except Exception as e: message = (_('Unknown error during import:') + ' %s: %s' % (type(e), unicode(e))) moreinfo = _('Resolve other errors first') messages.append(dict(info, type='error', message=message, moreinfo=moreinfo)) # Failed for some reason, perhaps due to invalid data supplied, # rollback savepoint and keep going cr.execute('ROLLBACK TO SAVEPOINT model_load_save') if any(message['type'] == 'error' for message in messages): cr.execute('ROLLBACK TO SAVEPOINT model_load') ids = False |
明白核心代码处理逻辑后,就可以在外层拦截并过滤错误数据继续提交干净数据以实现自动纠错导入,实现源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
''' author: i@renjie.me ''' original_load = models.Model.load @api.model def load(self, fields, data): load_result = original_load(self, fields, data) context = self.env.context or {} if context.get("import_ignore_error"): record = set() for message in load_result.get("messages", []): if message['type'] == 'error': record.add(message['record']) if record: data_ignore = [] for index, item in enumerate(data): if index not in record: data_ignore.append(item) load_result = original_load(self, fields, data_ignore) return load_result models.Model.load = load |