[IMP] enable loading custom models/fields and views from module data files

Loading views for custom models from module data files was not possible because
custom models and fields were introduced into the registry after all modules
were loaded.  As a consequence, the view architecture did not pass the checks.

This patch takes a different approach: custom models and fields are loaded
early on in the registry, so that views can be validated.  The trick is to take
special care of relational custom fields: we skip them if their comodel does
not appear in the registry.  This allows to install and upgrade modules that
create/modify custom models, fields and views for them.
This commit is contained in:
Raphael Collet 2014-12-16 17:20:20 +01:00
parent b0ae5eac57
commit 8f38a7806a
4 changed files with 23 additions and 13 deletions

View File

@ -446,6 +446,7 @@ class ir_model_fields(osv.osv):
for item in self.browse(cr, user, ids, context=context):
obj = self.pool.get(item.model)
field = getattr(obj, '_fields', {}).get(item.name)
if item.state != 'manual':
raise except_orm(_('Error!'),
@ -481,12 +482,12 @@ class ir_model_fields(osv.osv):
# We don't check the 'state', because it might come from the context
# (thus be set for multiple fields) and will be ignored anyway.
if obj is not None:
if obj is not None and field is not None:
# find out which properties (per model) we need to update
for field_name, prop_name, func in model_props:
if field_name in vals:
prop_value = func(vals[field_name])
if getattr(obj._fields[item.name], prop_name) != prop_value:
if getattr(field, prop_name) != prop_value:
patches[obj][final_name][prop_name] = prop_value
# These shall never be written (modified)

View File

@ -705,7 +705,7 @@ class BaseModel(object):
pool._store_function[model].sort(key=lambda x: x[4])
@classmethod
def _init_manual_fields(cls, cr):
def _init_manual_fields(cls, cr, partial=False):
# Check whether the query is already done
if cls.pool.fields_by_model is not None:
manual_fields = cls.pool.fields_by_model.get(cls._name, [])
@ -729,14 +729,20 @@ class BaseModel(object):
elif field['ttype'] in ('selection', 'reference'):
attrs['selection'] = eval(field['selection'])
elif field['ttype'] == 'many2one':
if partial and field['relation'] not in cls.pool:
continue
attrs['comodel_name'] = field['relation']
attrs['ondelete'] = field['on_delete']
attrs['domain'] = eval(field['domain']) if field['domain'] else None
elif field['ttype'] == 'one2many':
if partial and field['relation'] not in cls.pool:
continue
attrs['comodel_name'] = field['relation']
attrs['inverse_name'] = field['relation_field']
attrs['domain'] = eval(field['domain']) if field['domain'] else None
elif field['ttype'] == 'many2many':
if partial and field['relation'] not in cls.pool:
continue
attrs['comodel_name'] = field['relation']
_rel1 = field['relation'].replace('.', '_')
_rel2 = field['model'].replace('.', '_')
@ -2939,8 +2945,11 @@ class BaseModel(object):
field.reset()
@api.model
def _setup_fields(self):
""" Setup the fields (dependency triggers, etc). """
def _setup_fields(self, partial=False):
""" Setup the fields (dependency triggers, etc).
:param partial: ``True`` if all models have not been loaded yet.
"""
cls = type(self)
if cls._setup_done:
return
@ -2951,8 +2960,7 @@ class BaseModel(object):
self.env[parent]._setup_fields()
# retrieve custom fields
if not self._context.get('_setup_fields_partial'):
cls._init_manual_fields(self._cr)
cls._init_manual_fields(self._cr, partial=partial)
# retrieve inherited fields
cls._inherits_check()

View File

@ -360,10 +360,6 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
['to install'], force, status, report,
loaded_modules, update_module)
# load custom models
cr.execute('select model from ir_model where state=%s', ('manual',))
for model in cr.dictfetchall():
registry['ir.model'].instanciate(cr, SUPERUSER_ID, model['model'], {})
registry.setup_models(cr)
# STEP 4: Finish and cleanup installations

View File

@ -158,15 +158,20 @@ class Registry(Mapping):
:param partial: ``True`` if all models have not been loaded yet.
"""
# load custom models
ir_model = self['ir.model']
cr.execute('select model from ir_model where state=%s', ('manual',))
for (model_name,) in cr.fetchall():
ir_model.instanciate(cr, SUPERUSER_ID, model_name, {})
# prepare the setup on all models
for model in self.models.itervalues():
model._prepare_setup_fields(cr, SUPERUSER_ID)
# do the actual setup from a clean state
self._m2m = {}
context = {'_setup_fields_partial': partial}
for model in self.models.itervalues():
model._setup_fields(cr, SUPERUSER_ID, context=context)
model._setup_fields(cr, SUPERUSER_ID, partial=partial)
def clear_caches(self):
""" Clear the caches