[FIX] ir_models: fix registry when we add/remove/modify a custom model/field
This commit is contained in:
parent
9696d76aec
commit
24f26c0eeb
|
@ -26,9 +26,9 @@ import time
|
||||||
import types
|
import types
|
||||||
|
|
||||||
import openerp
|
import openerp
|
||||||
import openerp.modules.registry
|
|
||||||
from openerp import SUPERUSER_ID
|
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 import fields, osv
|
||||||
from openerp.osv.orm import BaseModel, Model, MAGIC_COLUMNS, except_orm
|
from openerp.osv.orm import BaseModel, Model, MAGIC_COLUMNS, except_orm
|
||||||
from openerp.tools import config
|
from openerp.tools import config
|
||||||
|
@ -181,8 +181,8 @@ class ir_model(osv.osv):
|
||||||
# only reload pool for normal unlink. For module uninstall the
|
# only reload pool for normal unlink. For module uninstall the
|
||||||
# reload is done independently in openerp.modules.loading
|
# reload is done independently in openerp.modules.loading
|
||||||
cr.commit() # must be committed before reloading registry in new cursor
|
cr.commit() # must be committed before reloading registry in new cursor
|
||||||
openerp.modules.registry.RegistryManager.new(cr.dbname)
|
RegistryManager.new(cr.dbname)
|
||||||
openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname)
|
RegistryManager.signal_registry_change(cr.dbname)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
@ -205,8 +205,6 @@ class ir_model(osv.osv):
|
||||||
if vals.get('state','base')=='manual':
|
if vals.get('state','base')=='manual':
|
||||||
self.instanciate(cr, user, vals['model'], context)
|
self.instanciate(cr, user, vals['model'], context)
|
||||||
model = self.pool[vals['model']]
|
model = self.pool[vals['model']]
|
||||||
model._prepare_setup_fields(cr, SUPERUSER_ID)
|
|
||||||
model._setup_fields(cr, SUPERUSER_ID)
|
|
||||||
ctx = dict(context,
|
ctx = dict(context,
|
||||||
field_name=vals['name'],
|
field_name=vals['name'],
|
||||||
field_state='manual',
|
field_state='manual',
|
||||||
|
@ -214,25 +212,25 @@ class ir_model(osv.osv):
|
||||||
update_custom_fields=True)
|
update_custom_fields=True)
|
||||||
model._auto_init(cr, ctx)
|
model._auto_init(cr, ctx)
|
||||||
model._auto_end(cr, ctx) # actually create FKs!
|
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
|
return res
|
||||||
|
|
||||||
def instanciate(self, cr, user, model, context=None):
|
def instanciate(self, cr, user, model, context=None):
|
||||||
class x_custom_model(osv.osv):
|
|
||||||
_custom = True
|
|
||||||
if isinstance(model, unicode):
|
if isinstance(model, unicode):
|
||||||
model = model.encode('utf-8')
|
model = model.encode('utf-8')
|
||||||
x_custom_model._name = model
|
|
||||||
x_custom_model._module = False
|
class CustomModel(models.Model):
|
||||||
a = x_custom_model._build_model(self.pool, cr)
|
_name = model
|
||||||
if not a._columns:
|
_module = False
|
||||||
x_name = 'id'
|
_custom = True
|
||||||
elif 'x_name' in a._columns.keys():
|
|
||||||
x_name = 'x_name'
|
obj = CustomModel._build_model(self.pool, cr)
|
||||||
else:
|
obj._rec_name = CustomModel._rec_name = (
|
||||||
x_name = a._columns.keys()[0]
|
'x_name' if 'x_name' in obj._columns else
|
||||||
x_custom_model._rec_name = x_name
|
list(obj._columns)[0] if obj._columns else
|
||||||
a._rec_name = x_name
|
'id'
|
||||||
|
)
|
||||||
|
|
||||||
class ir_model_fields(osv.osv):
|
class ir_model_fields(osv.osv):
|
||||||
_name = 'ir.model.fields'
|
_name = 'ir.model.fields'
|
||||||
|
@ -329,15 +327,15 @@ class ir_model_fields(osv.osv):
|
||||||
column_name = cr.fetchone()
|
column_name = cr.fetchone()
|
||||||
if column_name and (result and result[0] == 'r'):
|
if column_name and (result and result[0] == 'r'):
|
||||||
cr.execute('ALTER table "%s" DROP column "%s" cascade' % (model._table, field.name))
|
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
|
# remove m2m relation table for custom fields
|
||||||
# we consider the m2m relation is only one way as it's not possible
|
# 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
|
# to specify the relation table in the interface for custom fields
|
||||||
# TODO master: maybe use ir.model.relations for custom fields
|
# TODO master: maybe use ir.model.relations for custom fields
|
||||||
if field.state == 'manual' and field.ttype == 'many2many':
|
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))
|
cr.execute('DROP table "%s"' % (rel_name))
|
||||||
|
model._pop_field(field.name)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def unlink(self, cr, user, ids, context=None):
|
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)
|
res = super(ir_model_fields, self).unlink(cr, user, ids, context)
|
||||||
if not context.get(MODULE_UNINSTALL_FLAG):
|
if not context.get(MODULE_UNINSTALL_FLAG):
|
||||||
cr.commit()
|
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
|
return res
|
||||||
|
|
||||||
def create(self, cr, user, vals, context=None):
|
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:
|
if self.pool.fields_by_model is not None:
|
||||||
cr.execute('SELECT * FROM ir_model_fields WHERE id=%s', (res,))
|
cr.execute('SELECT * FROM ir_model_fields WHERE id=%s', (res,))
|
||||||
self.pool.fields_by_model.setdefault(vals['model'], []).append(cr.dictfetchone())
|
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
|
#Added context to _auto_init for special treatment to custom field for select_level
|
||||||
ctx = dict(context,
|
ctx = dict(context,
|
||||||
field_name=vals['name'],
|
field_name=vals['name'],
|
||||||
|
@ -396,7 +393,8 @@ class ir_model_fields(osv.osv):
|
||||||
update_custom_fields=True)
|
update_custom_fields=True)
|
||||||
model._auto_init(cr, ctx)
|
model._auto_init(cr, ctx)
|
||||||
model._auto_end(cr, ctx) # actually create FKs!
|
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
|
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)
|
res = super(ir_model_fields,self).write(cr, user, ids, vals, context=context)
|
||||||
|
|
||||||
if column_rename:
|
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:
|
# This is VERY risky, but let us have this feature:
|
||||||
# we want to change the key of column in obj._columns dict
|
# we want to change the key of field in obj._fields and obj._columns
|
||||||
col = column_rename[0]._columns.pop(column_rename[1][1]) # take object out, w/o copy
|
field = obj._pop_field(rename[1])
|
||||||
column_rename[0]._columns[column_rename[1][2]] = col
|
obj._add_field(rename[2], field)
|
||||||
|
|
||||||
if models_patch:
|
if models_patch:
|
||||||
# We have to update _columns of the model(s) and then call their
|
# 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():
|
for __, patch_struct in models_patch.items():
|
||||||
obj = patch_struct[0]
|
obj = patch_struct[0]
|
||||||
|
# TODO: update new-style fields accordingly
|
||||||
for col_name, col_prop, val in patch_struct[1]:
|
for col_name, col_prop, val in patch_struct[1]:
|
||||||
setattr(obj._columns[col_name], col_prop, val)
|
setattr(obj._columns[col_name], col_prop, val)
|
||||||
obj._auto_init(cr, ctx)
|
obj._auto_init(cr, ctx)
|
||||||
obj._auto_end(cr, ctx) # actually create FKs!
|
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
|
return res
|
||||||
|
|
||||||
class ir_model_constraint(Model):
|
class ir_model_constraint(Model):
|
||||||
|
|
|
@ -478,6 +478,18 @@ class BaseModel(object):
|
||||||
# remove potential column that may be overridden by field
|
# remove potential column that may be overridden by field
|
||||||
cls._columns.pop(name, None)
|
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
|
@classmethod
|
||||||
def _add_magic_fields(cls):
|
def _add_magic_fields(cls):
|
||||||
""" Introduce magic fields on the current class
|
""" Introduce magic fields on the current class
|
||||||
|
|
Loading…
Reference in New Issue