From c244bdf4223bb284282abc7cc8f10d562305c9ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 11 Jun 2018 23:18:28 +0200 Subject: [PATCH] Clean ir.model and ir.model.field once every models have been registered The same model can be registered multiple times by one module so the cleaning can only happen when the all the classes have been registered. issue7500 review53271002 --- trytond/ir/model.py | 47 ++++++++++++++++++++++++++++++++++++- trytond/modules/__init__.py | 12 ++++++++-- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/trytond/ir/model.py b/trytond/ir/model.py index 2778bd3be4..a69f3b3ec9 100644 --- a/trytond/ir/model.py +++ b/trytond/ir/model.py @@ -1,8 +1,9 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. -import re import heapq import json +import logging +import re from sql import Null from sql.aggregate import Max @@ -33,6 +34,7 @@ __all__ = [ 'ModelData', 'PrintModelGraphStart', 'PrintModelGraph', 'ModelGraph', 'ModelWorkflowGraph', ] +logger = logging.getLogger(__name__) class Model(ModelSQL, ModelView): @@ -105,6 +107,26 @@ class Model(ModelSQL, ModelView): where=ir_model.id == model_id)) return model_id + @classmethod + def clean(cls): + pool = Pool() + transaction = Transaction() + cursor = transaction.connection.cursor() + ir_model = cls.__table__() + cursor.execute(*ir_model.select(ir_model.model, ir_model.id)) + for model, id_ in cursor: + try: + pool.get(model) + except KeyError: + logger.info("remove model: %s", model) + try: + cls.delete([cls(id_)]) + transaction.commit() + except Exception: + transaction.rollback() + logger.error( + "could not delete model: %s", model, exc_info=True) + @classmethod def list_models(cls): 'Return a list of all models names' @@ -259,6 +281,29 @@ class ModelField(ModelSQL, ModelView): where=ir_model_field.id == model_fields[field_name]['id'])) + @classmethod + def clean(cls): + pool = Pool() + IrModel = pool.get('ir.model') + transaction = Transaction() + cursor = transaction.connection.cursor() + ir_model = IrModel.__table__() + ir_model_field = cls.__table__() + cursor.execute(*ir_model_field + .join(ir_model, condition=ir_model_field.model == ir_model.id) + .select(ir_model.model, ir_model_field.name, ir_model_field.id)) + for model, field, id_ in cursor: + Model = pool.get(model) + if field not in Model._fields: + logger.info("remove field: %s.%s", model, field) + try: + cls.delete([cls(id_)]) + transaction.commit() + except Exception: + transaction.rollback() + logger.error( + "could not delete field: %s.%s", model, field, + exc_info=True) @staticmethod def default_name(): diff --git a/trytond/modules/__init__.py b/trytond/modules/__init__.py index 2ce376d889..d968d44c5c 100644 --- a/trytond/modules/__init__.py +++ b/trytond/modules/__init__.py @@ -215,7 +215,8 @@ def load_module_graph(graph, pool, update=None, lang=None): lang.add(code) code = get_parent_language(code) - with Transaction().connection.cursor() as cursor: + transaction = Transaction() + with transaction.connection.cursor() as cursor: modules = [x.name for x in graph] cursor.execute(*ir_module.select(ir_module.name, ir_module.state, where=ir_module.name.in_(modules))) @@ -296,10 +297,17 @@ def load_module_graph(graph, pool, update=None, lang=None): ])) module2state[package.name] = 'activated' - Transaction().connection.commit() + transaction.commit() if not update: pool.setup() + else: + # Remove unknown models and fields + Model = pool.get('ir.model') + Model.clean() + ModelField = pool.get('ir.model.field') + ModelField.clean() + transaction.commit() pool.setup_mixin(modules)