From 9e6df0fb71c1aa87afcc10e386d3b2c1a485a633 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Mon, 26 Oct 2020 15:35:40 +0000 Subject: [PATCH] [FIX] core: reinstall hooks after setting up models in registry Before this patch, adding a field on a custom model discards all automated actions on that model. The explanation is relatively simple. When models are set up in the registry, the classes of custom models are dropped then recreated. Given that automated actions are implemented as monkey-patches on model classes, the setup of models simply loses those monkey-patches, which explains why they stop working on custom models. The fix introduces an `_unregister_hook()` method, that is expected to clean up what has been done in `_register_hook()`. When the registry is ready (i.e., not being loaded), the setup of models first invokes `_unregister_hook()` on models, proceeds with the setup, and finally invokes `_register_hook()` to reinstall the hooks. OPW 2362308 closes odoo/odoo#60833 X-original-commit: 67152bf82da2674179297d32e4cec9dd534fa0c9 Signed-off-by: Raphael Collet (rco) --- odoo/models.py | 4 ++++ odoo/modules/loading.py | 4 ++++ odoo/modules/registry.py | 16 ++++++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/odoo/models.py b/odoo/models.py index 75e07d42357..d7705b1f898 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -4827,6 +4827,10 @@ Fields: """ stuff to do right after the registry is built """ pass + def _unregister_hook(self): + """ Clean up what `~._register_hook` has done. """ + pass + @classmethod def _patch_method(cls, name, method): """ Monkey-patch a method for all instances of this model. This replaces diff --git a/odoo/modules/loading.py b/odoo/modules/loading.py index 0b57aa83ab7..1f2c4df751d 100644 --- a/odoo/modules/loading.py +++ b/odoo/modules/loading.py @@ -567,6 +567,10 @@ def load_modules(db, force_demo=False, status=None, update_module=False): _logger.error('At least one test failed when loading the modules.') # STEP 8: call _register_hook on every model + # This is done *exactly once* when the registry is being loaded. See the + # management of those hooks in `Registry.setup_models`: all the calls to + # setup_models() done here do not mess up with hooks, as registry.ready + # is False. env = api.Environment(cr, SUPERUSER_ID, {}) for model in env.values(): model._register_hook() diff --git a/odoo/modules/registry.py b/odoo/modules/registry.py index 8ccb1615113..febae952129 100644 --- a/odoo/modules/registry.py +++ b/odoo/modules/registry.py @@ -236,10 +236,17 @@ class Registry(Mapping): """ Complete the setup of models. This must be called after loading modules and before using the ORM. """ + env = odoo.api.Environment(cr, SUPERUSER_ID, {}) + + # Uninstall registry hooks. Because of the condition, this only happens + # on a fully loaded registry, and not on a registry being loaded. + if self.ready: + for model in env.values(): + model._unregister_hook() + self.clear_caches() lazy_property.reset_all(self) self.registry_invalidated = True - env = odoo.api.Environment(cr, SUPERUSER_ID, {}) if env.all.tocompute: _logger.error( @@ -267,7 +274,12 @@ class Registry(Mapping): for model in models: model._setup_complete() - self.registry_invalidated = True + # Reinstall registry hooks. Because of the condition, this only happens + # on a fully loaded registry, and not on a registry being loaded. + if self.ready: + for model in env.values(): + model._register_hook() + env['base'].flush() @lazy_property def field_computed(self):