[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:
Christophe Simonis
2023-10-31 13:26:44 +00:00
parent d170e913ab
commit 35e22b8fe9
4 changed files with 91 additions and 1 deletions
+88
View File
@@ -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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
9 access_ir_model_group_erp_manager ir_model group_erp_manager model_ir_model group_erp_manager 1 1 1 1
10 access_ir_model_constraint_group_erp_manager ir_model_constraint group_erp_manager model_ir_model_constraint group_erp_manager 1 1 1 1
11 access_ir_model_relation_group_erp_manager ir_model_relation group_erp_manager model_ir_model_relation group_erp_manager 1 1 1 1
12 access_ir_model_inherit ir_model_inherit nobody model_ir_model_inherit 0 0 0 0
13 access_ir_model_access_group_erp_manager ir_model_access_group_erp_manager model_ir_model_access group_erp_manager 1 1 1 1
14 access_ir_model_data_group_erp_manager ir_model_data group_erp_manager model_ir_model_data group_erp_manager 1 1 1 1
15 access_ir_model_fields_group_erp_manager ir_model_fields group_erp_manager model_ir_model_fields group_erp_manager 1 1 1 1
+1 -1
View File
@@ -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({
+1
View File
@@ -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