[FIX] orm,registry: properly check m2o FKs during model update + fix some models `auto_init`ed multiple times
The case where no constraint existed at all was not working, and after fixing it, the ORM started to re-create the same constraints multiple times for some modules. This was for models that are split within a module (such as res.users in base, which is made of several small classes): all the partial models were going through _auto_init instead of only the final one - doing useless extra work. Unfortunately establishing the FK happens before the XML data files are loaded, so a number of FK and NOT NULL constraints failed to apply due to missing tables/records. base.sql had to be extended a bit to cover these cases in a minimalist fashion bzr revid: odo@openerp.com-20121217214645-av9n003yzterhujw
This commit is contained in:
parent
f827de7049
commit
9f77d2e2f4
|
@ -149,7 +149,6 @@ CREATE TABLE res_users (
|
|||
active boolean default True,
|
||||
login varchar(64) NOT NULL UNIQUE,
|
||||
password varchar(64) default null,
|
||||
lang varchar(64) default '',
|
||||
-- No FK references below, will be added later by ORM
|
||||
-- (when the destination rows exist)
|
||||
company_id int,
|
||||
|
@ -316,13 +315,29 @@ CREATE TABLE ir_module_module_dependency (
|
|||
primary key(id)
|
||||
);
|
||||
|
||||
CREATE TABLE res_company (
|
||||
CREATE TABLE res_partner (
|
||||
id serial NOT NULL,
|
||||
name character varying(64) not null,
|
||||
parent_id integer references res_company on delete set null,
|
||||
name character varying(128),
|
||||
lang varchar(64),
|
||||
company_id int,
|
||||
primary key(id)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE res_currency (
|
||||
id serial PRIMARY KEY,
|
||||
name VARCHAR(32) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE res_company (
|
||||
id serial PRIMARY KEY,
|
||||
name character varying(128) not null,
|
||||
parent_id integer references res_company on delete set null,
|
||||
partner_id integer not null references res_partner,
|
||||
currency_id integer not null references res_currency
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE res_lang (
|
||||
id serial PRIMARY KEY,
|
||||
name VARCHAR(64) NOT NULL UNIQUE,
|
||||
|
@ -375,16 +390,24 @@ CREATE TABLE ir_model_relation (
|
|||
module integer NOT NULL references ir_module_module on delete restrict,
|
||||
model integer NOT NULL references ir_model on delete restrict,
|
||||
name character varying(128) NOT NULL
|
||||
);
|
||||
);
|
||||
|
||||
---------------------------------
|
||||
-- Users
|
||||
---------------------------------
|
||||
insert into res_users (id,login,password,active,company_id,partner_id) VALUES (1,'admin','admin',true,1,1);
|
||||
insert into ir_model_data (name,module,model,noupdate,res_id) VALUES ('user_root','base','res.users',true,1);
|
||||
|
||||
insert into res_users (id,login,password,active,company_id,partner_id,lang) values (1,'admin','admin',True,1,1,'en_US');
|
||||
insert into ir_model_data (name,module,model,noupdate,res_id) values ('user_root','base','res.users',True,1);
|
||||
insert into res_partner (id, name, lang, company_id) VALUES (1, 'Your Company', 'en_US', 1);
|
||||
insert into ir_model_data (name,module,model,noupdate,res_id) VALUES ('main_partner','base','res.partner',true,1);
|
||||
|
||||
-- Compatibility purpose, to remove V6.0
|
||||
insert into ir_model_data (name,module,model,noupdate,res_id) values ('user_admin','base','res.users',True,1);
|
||||
insert into res_currency (id, name) VALUES (1, 'EUR');
|
||||
insert into ir_model_data (name,module,model,noupdate,res_id) VALUES ('EUR','base','res.currency',true,1);
|
||||
|
||||
insert into res_company (id, name, partner_id, currency_id) VALUES (1, 'Your Company', 1, 1);
|
||||
insert into ir_model_data (name,module,model,noupdate,res_id) VALUES ('main_company','base','res.company',true,1);
|
||||
|
||||
select setval('res_company_id_seq', 2);
|
||||
select setval('res_users_id_seq', 2);
|
||||
select setval('res_partner_id_seq', 2);
|
||||
select setval('res_currency_id_seq', 2);
|
|
@ -142,7 +142,7 @@ class res_users(osv.osv):
|
|||
'id': fields.integer('ID'),
|
||||
'login_date': fields.date('Latest connection', select=1),
|
||||
'partner_id': fields.many2one('res.partner', required=True,
|
||||
string='Related Partner', ondelete='cascade',
|
||||
string='Related Partner', ondelete='restrict',
|
||||
help='Partner-related data of the user'),
|
||||
'login': fields.char('Login', size=64, required=True,
|
||||
help="Used to log into the system"),
|
||||
|
|
|
@ -110,15 +110,16 @@ class Registry(object):
|
|||
and registers them in the registry.
|
||||
|
||||
"""
|
||||
|
||||
res = []
|
||||
|
||||
models_to_load = [] # need to preserve loading order
|
||||
# Instantiate registered classes (via the MetaModel automatic discovery
|
||||
# or via explicit constructor call), and add them to the pool.
|
||||
for cls in openerp.osv.orm.MetaModel.module_to_models.get(module.name, []):
|
||||
res.append(cls.create_instance(self, cr))
|
||||
|
||||
return res
|
||||
# models register themselves in self.models
|
||||
model = cls.create_instance(self, cr)
|
||||
if model._name not in models_to_load:
|
||||
# avoid double-loading models whose declaration is split
|
||||
models_to_load.append(model._name)
|
||||
return [self.models[m] for m in models_to_load]
|
||||
|
||||
def schedule_cron_jobs(self):
|
||||
""" Make the cron thread care about this registry/database jobs.
|
||||
|
|
|
@ -2890,15 +2890,15 @@ class BaseModel(object):
|
|||
# usually because they could block deletion due to the FKs.
|
||||
# So unless stated otherwise we default them to ondelete=cascade.
|
||||
ondelete = ondelete or 'cascade'
|
||||
self._foreign_keys.append((self._table, source_field, dest_model._table, ondelete or 'set null'))
|
||||
_schema.debug("Table '%s': added foreign key '%s' with definition=REFERENCES \"%s\" ON DELETE %s",
|
||||
self._table, source_field, dest_model._table, ondelete)
|
||||
fk_def = (self._table, source_field, dest_model._table, ondelete or 'set null')
|
||||
self._foreign_keys.add(fk_def)
|
||||
_schema.debug("Table '%s': added foreign key '%s' with definition=REFERENCES \"%s\" ON DELETE %s", *fk_def)
|
||||
|
||||
# unchecked version: for custom cases, such as m2m relationships
|
||||
def _m2o_add_foreign_key_unchecked(self, source_table, source_field, dest_model, ondelete):
|
||||
self._foreign_keys.append((source_table, source_field, dest_model._table, ondelete or 'set null'))
|
||||
_schema.debug("Table '%s': added foreign key '%s' with definition=REFERENCES \"%s\" ON DELETE %s",
|
||||
source_table, source_field, dest_model._table, ondelete)
|
||||
fk_def = (source_table, source_field, dest_model._table, ondelete or 'set null')
|
||||
self._foreign_keys.add(fk_def)
|
||||
_schema.debug("Table '%s': added foreign key '%s' with definition=REFERENCES \"%s\" ON DELETE %s", *fk_def)
|
||||
|
||||
def _drop_constraint(self, cr, source_table, constraint_name):
|
||||
cr.execute("ALTER TABLE %s DROP CONSTRAINT %s" % (source_table,constraint_name))
|
||||
|
@ -2929,18 +2929,22 @@ class BaseModel(object):
|
|||
cons, = constraints
|
||||
if cons['ondelete_rule'] != POSTGRES_CONFDELTYPES.get((ondelete or 'set null').upper(), 'a')\
|
||||
or cons['foreign_table'] != dest_model._table:
|
||||
# Wrong FK: drop it and recreate
|
||||
_schema.debug("Table '%s': dropping obsolete FK constraint: '%s'",
|
||||
source_table, cons['constraint_name'])
|
||||
self._drop_constraint(cr, source_table, cons['constraint_name'])
|
||||
self._m2o_add_foreign_key_checked(source_field, dest_model, ondelete)
|
||||
# else it's all good, nothing to do!
|
||||
else:
|
||||
# it's all good, nothing to do!
|
||||
return
|
||||
else:
|
||||
# Multiple FKs found for the same field, drop them all, and re-create
|
||||
for cons in constraints:
|
||||
_schema.debug("Table '%s': dropping duplicate FK constraints: '%s'",
|
||||
source_table, cons['constraint_name'])
|
||||
self._drop_constraint(cr, source_table, cons['constraint_name'])
|
||||
self._m2o_add_foreign_key_checked(source_field, dest_model, ondelete)
|
||||
|
||||
# (re-)create the FK
|
||||
self._m2o_add_foreign_key_checked(source_field, dest_model, ondelete)
|
||||
|
||||
|
||||
|
||||
|
@ -2962,7 +2966,7 @@ class BaseModel(object):
|
|||
_auto_end).
|
||||
|
||||
"""
|
||||
self._foreign_keys = []
|
||||
self._foreign_keys = set()
|
||||
raise_on_invalid_object_name(self._name)
|
||||
if context is None:
|
||||
context = {}
|
||||
|
|
Loading…
Reference in New Issue