-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[IMP] util/records: enforce cascade
removal for actions
#81
base: master
Are you sure you want to change the base?
Conversation
I do not intend to leave these NOTES in the final diff, these are only for discussions in this PR |
You could move the notes from the code to the PR. Add them as comments here. |
src/util/records.py
Outdated
@@ -351,10 +397,13 @@ def remove_record(cr, name): | |||
if model == "res.groups": | |||
_logger.log(NEARLYWARN, "Removing group %r", name) | |||
return remove_group(cr, group_id=res_id) | |||
|
|||
if model in get_models_inheriting_actions_actions(cr): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could have a hard-coded list of standard action models. We don't need to take into account all possible models extending the actions base model. We don't that for views for example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can just use for_each_inherit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my point in leaving it as a SQL query is not only to encompass custom models but also reduce the maintainability overhead in case there is any change in standard models. what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The SQL query version plus the query itself adds complexity, it's cleaner with for_each_inherit
, IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OTOH, the list of models that are problematic (the ones that are using INHERIT at PostgreSQL level) is known. We can hard-code it.
Note that this list changed over time, so we need to list all of them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the ones that are using INHERIT at PostgreSQL level
AFAIU, the issue also encompasses models that would inherit ir.actions.actions
without using psql's INHERIT
mechanism*, since this concerns fields to ir.actions.actions
(as a Polymorphism mechanism), and not its child classes.
*: I've just tested creating a new model inheriting from ir.actions.actions
, similar to the standard ones, and this new model's table does not have Inherits: ir_actions
, whereas the ones from standard do have.
So I understand that list of models returned by for_each_inherit
should be equal to the ones to be hard-coded (or used in a hard-coded list) for a specific version.
That said, having in mind that for_each_inherit
performs a SQL query itself, I believe that:
hard-coding > for_each_inherit
: more performaticfor_each_inherit > hard-coding
: easier to maintain
2019fa8
to
c9c4053
Compare
src/util/records.py
Outdated
"%r should point to a model inheriting from 'ir.actions.actions', not a %r" % (xml_id, model) | ||
) | ||
|
||
cr.execute("SELECT name, model FROM ir_model_fields WHERE relation = 'ir.actions.actions' AND on_delete ='cascade'") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should also search the one linking to the xmlid's model
cr.execute("SELECT name, model FROM ir_model_fields WHERE relation = 'ir.actions.actions' AND on_delete ='cascade'") | |
cr.execute("SELECT name, model FROM ir_model_fields WHERE relation IN %s AND on_delete ='cascade'", [tuple({model, "ir.actions.actions"})]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understood, maybe this is linked to the comment above?
I took the example of website.snippet.filter
that has a M2O field to ir.actions.server
. By examining it's table, we have:
Foreign-key constraints:
"website_snippet_filter_action_server_id_fkey" FOREIGN KEY (action_server_id) REFERENCES ir_act_server(id) ON DELETE CASCADE
"website_snippet_filter_create_uid_fkey" FOREIGN KEY (create_uid) REFERENCES res_users(id) ON DELETE SET NULL
"website_snippet_filter_filter_id_fkey" FOREIGN KEY (filter_id) REFERENCES ir_filters(id) ON DELETE CASCADE
"website_snippet_filter_website_id_fkey" FOREIGN KEY (website_id) REFERENCES website(id) ON DELETE CASCADE
"website_snippet_filter_write_uid_fkey" FOREIGN KEY (write_uid) REFERENCES res_users(id) ON DELETE SET NULL
That is, the foreign-key to ir.actions.server
is there (first line), so we can expect correct behaviour.
The issue is when we have a field to ir.actions.actions
for polymorphism.
If indeed a confusion happened, please let me know so I can improve the commit message.
c9c4053
to
e8ca86d
Compare
0e6707b
to
f293017
Compare
3d68a7a
to
9d3206b
Compare
9d3206b
to
8322013
Compare
8322013
to
af0ef5d
Compare
Can you add a test? |
2b59b0a
to
9fa89bd
Compare
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 when it is being referenced in favour of polymorphism; 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` if `ondelete=cascade`, or setting this field to NULL if `ondelete=set null`, when the action referenced in such field is removed using `upgrade-util`. Co-authored-by: Christophe Simonis <[email protected]>
9fa89bd
to
7fc1c85
Compare
Hey I believe we can revert the following PR https://github.com/odoo/upgrade/pull/5869 before this |
No, this is still needed for actions not deleted via this new helper. |
@KangOl @aj-fuentes ping 🏓 |
Any news here? I've discovered another issue with filters on an upgrade project, though it's not related to upgrading technically -> install a module, like hr_holidays, save a filter, uninstall the module = the filter is now corrupt because of the missing model in registry: IMO, apart from this util helper, either: 2 - I fix this in a PR to wdyt? @aj-fuentes @KangOl |
@erl-odoo The uninstall process of standard Odoo is full of corner cases where data is left in a wrong state, this is yet another example :) IMO yes you can try to fix the standard process to cleanup those filters in master odoo. During upgrades, removing what seems to be broken filters may be acceptable, but we usually try to avoid removing data (they may work in case the model re-appears after a reinstall). Generally speaking, if it was broken before the upgrade and doesn't fail the upgrade, we don't fix it. |
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 whenir.actions.actions
is a M2O field of another model; what leads to the not execution of some constraints, one of them being theondelete='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
withondelete=cascade
when the action referenced in such field is removed usingupgrade-util
.