[IMP] core: reflect the model inherits in the database
This will help the upgrade process. Currently, there is an harcoded[^1] inherit tree stored in the upgrade source. By storing this information in the databases, we: - avoid this hardcoded list. - support more than the standard modules. task-3504720 [^1]: hardcoded, but autogenerated. closes odoo/odoo#140261 Signed-off-by: Raphael Collet <rco@odoo.com>
This commit is contained in:
@@ -1319,6 +1319,94 @@ class IrModelFields(models.Model):
|
||||
field = self._get(model_name, field_name)
|
||||
return [(sel.value, sel.name) for sel in field.selection_ids]
|
||||
|
||||
|
||||
class ModelInherit(models.Model):
|
||||
_name = "ir.model.inherit"
|
||||
_description = "Model Inheritance Tree"
|
||||
_log_access = False
|
||||
|
||||
model_id = fields.Many2one("ir.model", required=True, ondelete="cascade")
|
||||
parent_id = fields.Many2one("ir.model", required=True, ondelete="cascade")
|
||||
parent_field_id = fields.Many2one("ir.model.fields", ondelete="cascade") # in case of inherits
|
||||
|
||||
_sql_constraints = [
|
||||
("uniq", "UNIQUE(model_id, parent_id)", "Models inherits from another only once")
|
||||
]
|
||||
|
||||
def _reflect_inherits(self, model_names):
|
||||
""" Reflect the given models' inherits (_inherit and _inherits). """
|
||||
IrModel = self.env["ir.model"]
|
||||
get_model_id = IrModel._get_id
|
||||
|
||||
module_mapping = defaultdict(list)
|
||||
for model_name in model_names:
|
||||
get_field_id = self.env["ir.model.fields"]._get_ids(model_name).get
|
||||
model_id = get_model_id(model_name)
|
||||
model = self.env[model_name]
|
||||
|
||||
for cls in reversed(type(model).mro()):
|
||||
if not models.is_definition_class(cls):
|
||||
continue
|
||||
|
||||
items = [
|
||||
(model_id, get_model_id(parent_name), None)
|
||||
for parent_name in cls._inherit
|
||||
if parent_name not in ("base", model_name)
|
||||
] + [
|
||||
(model_id, get_model_id(parent_name), get_field_id(field))
|
||||
for parent_name, field in cls._inherits.items()
|
||||
]
|
||||
|
||||
for item in items:
|
||||
module_mapping[item].append(cls._module)
|
||||
|
||||
if not module_mapping:
|
||||
return
|
||||
|
||||
cr = self.env.cr
|
||||
cr.execute(
|
||||
"""
|
||||
SELECT i.id, i.model_id, i.parent_id, i.parent_field_id
|
||||
FROM ir_model_inherit i
|
||||
JOIN ir_model m
|
||||
ON m.id = i.model_id
|
||||
WHERE m.model IN %s
|
||||
""",
|
||||
[tuple(model_names)]
|
||||
)
|
||||
existing = {}
|
||||
inh_ids = {}
|
||||
for iid, model_id, parent_id, parent_field_id in cr.fetchall():
|
||||
inh_ids[(model_id, parent_id, parent_field_id)] = iid
|
||||
existing[(model_id, parent_id)] = parent_field_id
|
||||
|
||||
sentinel = object()
|
||||
cols = ["model_id", "parent_id", "parent_field_id"]
|
||||
rows = [item for item in module_mapping if existing.get(item[:2], sentinel) != item[2]]
|
||||
if rows:
|
||||
ids = upsert_en(self, cols, rows, ["model_id", "parent_id"])
|
||||
for row, id_ in zip(rows, ids):
|
||||
inh_ids[row] = id_
|
||||
self.pool.post_init(mark_modified, self.browse(ids), cols[1:])
|
||||
|
||||
# update their XML id
|
||||
IrModel.browse(id_ for item in module_mapping for id_ in item[:2]).fetch(['model'])
|
||||
data_list = []
|
||||
for (model_id, parent_id, parent_field_id), modules in module_mapping.items():
|
||||
model_name = IrModel.browse(model_id).model.replace(".", "_")
|
||||
parent_name = IrModel.browse(parent_id).model.replace(".", "_")
|
||||
record_id = inh_ids[(model_id, parent_id, parent_field_id)]
|
||||
data_list += [
|
||||
{
|
||||
"xml_id": f"{module}.model_inherit__{model_name}__{parent_name}",
|
||||
"record": self.browse(record_id),
|
||||
}
|
||||
for module in modules
|
||||
]
|
||||
|
||||
self.env["ir.model.data"]._update_xmlids(data_list)
|
||||
|
||||
|
||||
class IrModelSelection(models.Model):
|
||||
_name = 'ir.model.fields.selection'
|
||||
_order = 'sequence, id'
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"access_ir_model_group_erp_manager","ir_model group_erp_manager","model_ir_model","group_erp_manager",1,1,1,1
|
||||
"access_ir_model_constraint_group_erp_manager","ir_model_constraint group_erp_manager","model_ir_model_constraint","group_erp_manager",1,1,1,1
|
||||
"access_ir_model_relation_group_erp_manager","ir_model_relation group_erp_manager","model_ir_model_relation","group_erp_manager",1,1,1,1
|
||||
"access_ir_model_inherit","ir_model_inherit nobody","model_ir_model_inherit",,0,0,0,0
|
||||
"access_ir_model_access_group_erp_manager","ir_model_access_group_erp_manager","model_ir_model_access","group_erp_manager",1,1,1,1
|
||||
"access_ir_model_data_group_erp_manager","ir_model_data group_erp_manager","model_ir_model_data","group_erp_manager",1,1,1,1
|
||||
"access_ir_model_fields_group_erp_manager","ir_model_fields group_erp_manager","model_ir_model_fields","group_erp_manager",1,1,1,1
|
||||
|
||||
|
@@ -735,7 +735,7 @@ class TestCustomFields(TestCommonCustomFields):
|
||||
|
||||
# create a non-computed field, and assert how many queries it takes
|
||||
model_id = self.env['ir.model']._get_id('res.partner')
|
||||
query_count = 38
|
||||
query_count = 44
|
||||
with self.assertQueryCount(query_count):
|
||||
self.env.registry.clear_cache()
|
||||
self.env['ir.model.fields'].create({
|
||||
|
||||
@@ -573,6 +573,7 @@ class Registry(Mapping):
|
||||
env['ir.model.fields']._reflect_fields(model_names)
|
||||
env['ir.model.fields.selection']._reflect_selections(model_names)
|
||||
env['ir.model.constraint']._reflect_constraints(model_names)
|
||||
env['ir.model.inherit']._reflect_inherits(model_names)
|
||||
|
||||
self._ordinary_tables = None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user