From 24f26c0eebc0b9b55aed91f594ab6916eedf43c3 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Wed, 24 Sep 2014 11:28:28 +0200 Subject: [PATCH] [FIX] ir_models: fix registry when we add/remove/modify a custom model/field --- openerp/addons/base/ir/ir_model.py | 70 +++++++++++++++++++----------------- openerp/models.py | 12 +++++++ 2 files changed, 49 insertions(+), 33 deletions(-) diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 2007092..f1f2bfc 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -26,9 +26,9 @@ import time import types import openerp -import openerp.modules.registry from openerp import SUPERUSER_ID -from openerp import tools +from openerp import models, tools +from openerp.modules.registry import RegistryManager from openerp.osv import fields, osv from openerp.osv.orm import BaseModel, Model, MAGIC_COLUMNS, except_orm from openerp.tools import config @@ -181,8 +181,8 @@ class ir_model(osv.osv): # only reload pool for normal unlink. For module uninstall the # reload is done independently in openerp.modules.loading cr.commit() # must be committed before reloading registry in new cursor - openerp.modules.registry.RegistryManager.new(cr.dbname) - openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) + RegistryManager.new(cr.dbname) + RegistryManager.signal_registry_change(cr.dbname) return res @@ -205,8 +205,6 @@ class ir_model(osv.osv): if vals.get('state','base')=='manual': self.instanciate(cr, user, vals['model'], context) model = self.pool[vals['model']] - model._prepare_setup_fields(cr, SUPERUSER_ID) - model._setup_fields(cr, SUPERUSER_ID) ctx = dict(context, field_name=vals['name'], field_state='manual', @@ -214,25 +212,25 @@ class ir_model(osv.osv): update_custom_fields=True) model._auto_init(cr, ctx) model._auto_end(cr, ctx) # actually create FKs! - openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) + self.pool.setup_models(cr, partial=(not self.pool.ready)) + RegistryManager.signal_registry_change(cr.dbname) return res def instanciate(self, cr, user, model, context=None): - class x_custom_model(osv.osv): - _custom = True if isinstance(model, unicode): model = model.encode('utf-8') - x_custom_model._name = model - x_custom_model._module = False - a = x_custom_model._build_model(self.pool, cr) - if not a._columns: - x_name = 'id' - elif 'x_name' in a._columns.keys(): - x_name = 'x_name' - else: - x_name = a._columns.keys()[0] - x_custom_model._rec_name = x_name - a._rec_name = x_name + + class CustomModel(models.Model): + _name = model + _module = False + _custom = True + + obj = CustomModel._build_model(self.pool, cr) + obj._rec_name = CustomModel._rec_name = ( + 'x_name' if 'x_name' in obj._columns else + list(obj._columns)[0] if obj._columns else + 'id' + ) class ir_model_fields(osv.osv): _name = 'ir.model.fields' @@ -329,15 +327,15 @@ class ir_model_fields(osv.osv): column_name = cr.fetchone() if column_name and (result and result[0] == 'r'): cr.execute('ALTER table "%s" DROP column "%s" cascade' % (model._table, field.name)) - model._columns.pop(field.name, None) - # remove m2m relation table for custom fields # we consider the m2m relation is only one way as it's not possible # to specify the relation table in the interface for custom fields # TODO master: maybe use ir.model.relations for custom fields if field.state == 'manual' and field.ttype == 'many2many': - rel_name = self.pool[field.model]._all_columns[field.name].column._rel + rel_name = model._fields[field.name].relation cr.execute('DROP table "%s"' % (rel_name)) + model._pop_field(field.name) + return True def unlink(self, cr, user, ids, context=None): @@ -353,7 +351,8 @@ class ir_model_fields(osv.osv): res = super(ir_model_fields, self).unlink(cr, user, ids, context) if not context.get(MODULE_UNINSTALL_FLAG): cr.commit() - openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) + self.pool.setup_models(cr, partial=(not self.pool.ready)) + RegistryManager.signal_registry_change(cr.dbname) return res def create(self, cr, user, vals, context=None): @@ -384,10 +383,8 @@ class ir_model_fields(osv.osv): if self.pool.fields_by_model is not None: cr.execute('SELECT * FROM ir_model_fields WHERE id=%s', (res,)) self.pool.fields_by_model.setdefault(vals['model'], []).append(cr.dictfetchone()) - model.__init__(self.pool, cr) - model._prepare_setup_fields(cr, SUPERUSER_ID) - model._setup_fields(cr, SUPERUSER_ID) + model.__init__(self.pool, cr) #Added context to _auto_init for special treatment to custom field for select_level ctx = dict(context, field_name=vals['name'], @@ -396,7 +393,8 @@ class ir_model_fields(osv.osv): update_custom_fields=True) model._auto_init(cr, ctx) model._auto_end(cr, ctx) # actually create FKs! - openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) + self.pool.setup_models(cr, partial=(not self.pool.ready)) + RegistryManager.signal_registry_change(cr.dbname) return res @@ -490,11 +488,12 @@ class ir_model_fields(osv.osv): res = super(ir_model_fields,self).write(cr, user, ids, vals, context=context) if column_rename: - cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO "%s"' % column_rename[1]) + obj, rename = column_rename + cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO "%s"' % rename) # This is VERY risky, but let us have this feature: - # we want to change the key of column in obj._columns dict - col = column_rename[0]._columns.pop(column_rename[1][1]) # take object out, w/o copy - column_rename[0]._columns[column_rename[1][2]] = col + # we want to change the key of field in obj._fields and obj._columns + field = obj._pop_field(rename[1]) + obj._add_field(rename[2], field) if models_patch: # We have to update _columns of the model(s) and then call their @@ -507,11 +506,16 @@ class ir_model_fields(osv.osv): for __, patch_struct in models_patch.items(): obj = patch_struct[0] + # TODO: update new-style fields accordingly for col_name, col_prop, val in patch_struct[1]: setattr(obj._columns[col_name], col_prop, val) obj._auto_init(cr, ctx) obj._auto_end(cr, ctx) # actually create FKs! - openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) + + if column_rename or models_patch: + self.pool.setup_models(cr, partial=(not self.pool.ready)) + RegistryManager.signal_registry_change(cr.dbname) + return res class ir_model_constraint(Model): diff --git a/openerp/models.py b/openerp/models.py index 6647502..360c220 100644 --- a/openerp/models.py +++ b/openerp/models.py @@ -479,6 +479,18 @@ class BaseModel(object): cls._columns.pop(name, None) @classmethod + def _pop_field(cls, name): + """ Remove the field with the given `name` from the model. + This method should only be used for manual fields. + """ + field = cls._fields.pop(name) + cls._columns.pop(name, None) + cls._all_columns.pop(name, None) + if hasattr(cls, name): + delattr(cls, name) + return field + + @classmethod def _add_magic_fields(cls): """ Introduce magic fields on the current class -- 1.7.10.4