Skip to content

Commit e8ca86d

Browse files
committed
[IMP] util/records: enforce cascade removal for actions
The implementation of the python inheritance mechanism between the base class `ir.actions.actions` and its child classes (eg. `ir.actions.act_window`) does not allow the creation of foreign keys when `ir.actions.actions` is a M2O field of another model; what leads to the not execution of some constraints, one of them being the `ondelete='cascade'` constraint, which is set in PSQL level. That said, when a `ir.actions.actions` record is deleted, if it is being referenced as a M2O field by another model (eg. `ir.filters`), records from this second model won't be affected, what leads to undesired behaviour: a MissingError in the UI, indicating that the action was deleted. Such behaviour of not creating foreign keys and thus constraints is specific to `ir.actions.actions`. This commit remedies this specific case, removing records with a M2O field to `ir.actions.actions` with `ondelete=cascade` when the action referenced in such field is removed using `upgrade-util`.
1 parent 3787631 commit e8ca86d

File tree

1 file changed

+52
-1
lines changed

1 file changed

+52
-1
lines changed

src/util/records.py

+52-1
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,54 @@ def remove_asset(cr, name):
309309
remove_view(cr, name, silent=True)
310310
# fmt:on
311311

312+
def get_models_inheriting_actions_actions(cr):
313+
cr.execute(
314+
"""
315+
SELECT child_model.model
316+
FROM ir_model AS child_model
317+
JOIN ir_model_inherit
318+
ON child_model.id = ir_model_inherit.model_id
319+
JOIN ir_model AS base_model
320+
ON ir_model_inherit.parent_id = base_model.id
321+
WHERE base_model.model = 'ir.actions.actions'
322+
"""
323+
)
324+
return cr.fetchall()
325+
326+
def remove_action(cr, xml_id=None, action_id=None):
327+
assert bool(xml_id) ^ bool(action_id)
328+
329+
if xml_id:
330+
action_id = ref(cr, xml_id)
331+
332+
if action_id:
333+
module, _, name = xml_id.partition(".")
334+
cr.execute("SELECT model FROM ir_model_data WHERE module=%s AND name=%s", [module, name])
335+
[model] = cr.fetchone()
336+
if not model in get_models_inheriting_actions_actions(cr):
337+
raise ValueError(
338+
"%r should point to a model inheriting from 'ir.actions.actions', not a %r" % (xml_id, model)
339+
)
340+
341+
cr.execute(
342+
"""
343+
SELECT name,
344+
model,
345+
on_delete
346+
FROM ir_model_fields
347+
WHERE relation = 'ir.actions.actions'
348+
AND on_delete IN ( 'cascade', 'set null' )
349+
"""
350+
)
351+
352+
for column_name, model, on_delete in cr.fetchall():
353+
model_table = table_of_model(cr, model)
354+
if on_delete == 'cascade':
355+
query = format_query(cr, "DELETE FROM {} WHERE {} = %s", model_table, column_name)
356+
else:
357+
query = format_query(cr, "UPDATE {} SET {} = NULL WHERE {} = %s", model_table, column_name, column_name)
358+
cr.execute(query, (action_id,))
359+
312360

313361
def remove_record(cr, name):
314362
"""
@@ -351,10 +399,13 @@ def remove_record(cr, name):
351399
if model == "res.groups":
352400
_logger.log(NEARLYWARN, "Removing group %r", name)
353401
return remove_group(cr, group_id=res_id)
402+
403+
if model in get_models_inheriting_actions_actions(cr):
404+
_logger.log(NEARLYWARN, "Removing action %r", name)
405+
return remove_action(cr, action_id=res_id)
354406

355407
return remove_records(cr, model, [res_id])
356408

357-
358409
def remove_records(cr, model, ids):
359410
if not ids:
360411
return

0 commit comments

Comments
 (0)