diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index ad0912a59ee..6da5846bf89 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -580,7 +580,6 @@ class ir_model_data(osv.osv): def __init__(self, pool, cr): osv.osv.__init__(self, pool, cr) self.doinit = True - self.unlink_mark = {} # also stored in pool to avoid being discarded along with this osv instance if getattr(pool, 'model_data_reference_ids', None) is None: @@ -629,6 +628,14 @@ class ir_model_data(osv.osv): id = False return id + def unlink(self, cr, uid, ids, context=None): + """ Regular unlink method, but make sure to clear the caches. """ + ref_ids = self.browse(cr, uid, ids, context=context) + for ref_id in ref_ids: + self._get_id.clear_cache(cr.dbname, uid, ref_id.module, ref_id.name) + self.get_object_reference.clear_cache(cr.dbname, uid, ref_id.module, ref_id.name) + return super(ir_model_data,self).unlink(cr, uid, ids, context=context) + def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False, context=None): model_obj = self.pool.get(model) if not context: @@ -719,12 +726,6 @@ class ir_model_data(osv.osv): table.replace('.', '_'))] = (table, inherit_id) return res_id - def _unlink(self, cr, uid, model, res_ids): - for res_id in res_ids: - self.unlink_mark[(model, res_id)] = False - cr.execute('delete from ir_model_data where res_id=%s and model=%s', (res_id, model)) - return True - def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None, xml_id=False): if type(models[0])==type([]) or type(models[0])==type(()): model,res_id = models[0] @@ -752,15 +753,25 @@ class ir_model_data(osv.osv): return True def _process_end(self, cr, uid, modules): + """ Clear records removed from updated module data. + + This method is called at the end of the module loading process. + It is meant to removed records that are no longer present in the + updated data. Such records are recognised as the one with an xml id + and a module in ir_model_data and noupdate set to false, but not + present in self.loads. + + """ if not modules: return True modules = list(modules) module_in = ",".join(["%s"] * len(modules)) cr.execute('select id,name,model,res_id,module from ir_model_data where module IN (' + module_in + ') and noupdate=%s', modules + [False]) wkf_todo = [] + to_unlink = [] for (id, name, model, res_id,module) in cr.fetchall(): if (module,name) not in self.loads: - self.unlink_mark[(model,res_id)] = id + to_unlink.append((model,res_id)) if model=='workflow.activity': cr.execute('select res_type,res_id from wkf_instance where id IN (select inst_id from wkf_workitem where act_id=%s)', (res_id,)) wkf_todo.extend(cr.fetchall()) @@ -773,36 +784,19 @@ class ir_model_data(osv.osv): cr.commit() if not config.get('import_partial'): - for (model, res_id) in self.unlink_mark.keys(): + for (model, res_id) in to_unlink: if self.pool.get(model): self.__logger.info('Deleting %s@%s', res_id, model) try: self.pool.get(model).unlink(cr, uid, [res_id]) - if id: - ids = self.search(cr, uid, [('res_id','=',res_id), - ('model','=',model)]) - self.__logger.debug('=> Deleting %s: %s', - self._name, ids) - if len(ids) > 1 and \ - self.__logger.isEnabledFor(logging.WARNING): - self.__logger.warn( - 'Got %d %s for (%s, %d): %s', - len(ids), self._name, model, res_id, - map(itemgetter('module','name'), - self.read(cr, uid, ids, - ['name', 'module']))) - self.unlink(cr, uid, ids) - cr.execute( - 'DELETE FROM ir_values WHERE value=%s', - ('%s,%s'%(model, res_id),)) cr.commit() except Exception: cr.rollback() self.__logger.warn( - 'Could not delete id: %d of model %s\nThere ' - 'should be some relation that points to this ' - 'resource\nYou should manually fix this and ' - 'restart with --update=module', res_id, model) + 'Could not delete obsolete record with id: %d of model %s\n' + 'There should be some relation that points to this resource\n' + 'You should manually fix this and restart with --update=module', + res_id, model) return True ir_model_data() diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 6451dc67186..4141176fc5b 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -3511,9 +3511,10 @@ class orm(orm_template): # Removing the ir_model_data reference if the record being deleted is a record created by xml/csv file, # as these are not connected with real database foreign keys, and would be dangling references. # Step 1. Calling unlink of ir_model_data only for the affected IDS. - referenced_ids = pool_model_data.search(cr, uid, [('res_id','in',list(sub_ids)),('model','=',self._name)], context=context) + reference_ids = pool_model_data.search(cr, uid, [('res_id','in',list(sub_ids)),('model','=',self._name)], context=context) # Step 2. Marching towards the real deletion of referenced records - pool_model_data.unlink(cr, uid, referenced_ids, context=context) + if reference_ids: + pool_model_data.unlink(cr, uid, reference_ids, context=context) # For the same reason, removing the record relevant to ir_values ir_value_ids = ir_values_obj.search(cr, uid, diff --git a/openerp/tools/convert.py b/openerp/tools/convert.py index 9a24ac78e6d..d0e6b503142 100644 --- a/openerp/tools/convert.py +++ b/openerp/tools/convert.py @@ -301,14 +301,12 @@ form: module.record_id""" % (xml_id,) pass if ids: self.pool.get(d_model).unlink(cr, self.uid, ids) - self.pool.get('ir.model.data')._unlink(cr, self.uid, d_model, ids) def _remove_ir_values(self, cr, name, value, model): ir_values_obj = self.pool.get('ir.values') ir_value_ids = ir_values_obj.search(cr, self.uid, [('name','=',name),('value','=',value),('model','=',model)]) if ir_value_ids: ir_values_obj.unlink(cr, self.uid, ir_value_ids) - self.pool.get('ir.model.data')._unlink(cr, self.uid, 'ir.values', ir_value_ids) return True diff --git a/openerp/tools/yaml_import.py b/openerp/tools/yaml_import.py index ff4029d1f15..1c6a54c63b0 100644 --- a/openerp/tools/yaml_import.py +++ b/openerp/tools/yaml_import.py @@ -643,7 +643,6 @@ class YamlInterpreter(object): ids = [self.get_id(node.id)] if len(ids): self.pool.get(node.model).unlink(self.cr, self.uid, ids) - self.pool.get('ir.model.data')._unlink(self.cr, 1, node.model, ids) else: self.logger.log(logging.TEST, "Record not deleted.")