The issue occurs when a computed field depends on a many2many field with
a corresponding inverse field on its comodel. Consider two models like
class User(models.Model):
_name = _description = 'test_new_api.user'
group_ids = fields.Many2many('test_new_api.group')
group_count = fields.Integer(compute='_compute_group_count', store=True)
@api.depends('group_ids')
def _compute_group_count(self):
for user in self:
user.group_count = len(user.group_ids)
class Group(models.Model):
_name = _description = 'test_new_api.group'
user_ids = fields.Many2many('test_new_api.user')
When a user is added to a group with
group.write({'user_ids': [Command.link(user.id)]})
we expect the field `group_count` to be recomputed on `user` only, but
it is actually triggered on *all* the records in `group.user_ids`. This
is a real performance issue when there are many records in the relation.
The explanation comes from the fact that
- the framework considers the field `user_ids` is modified on `group`;
- the field `group_count` implicitly depends on `group_ids.user_ids`,
which makes it triggered on the users `u` such that `u.group_ids`
intersects `group`.
The solution consists in handling the dependencies on inverse many2many
field in the field itself. The field no longer adds the implicit
dependency on its inverse field in the trigger tree, but instead
determines which records in the comodel are actually impacted by the
relation change in the method field.write().
closes odoo/odoo#111943
X-original-commit: bb3a6e378b5f6b2e14b74ce4efb6d749ad54cb1e
Signed-off-by: Raphael Collet <rco@odoo.com>
12 KiB
12 KiB
| 1 | id | name | model_id:id | group_id:id | perm_read | perm_write | perm_create | perm_unlink |
|---|---|---|---|---|---|---|---|---|
| 2 | access_category | test_new_api_category | test_new_api.model_test_new_api_category | 1 | 1 | 1 | 1 | |
| 3 | access_decimal_precision_test_all | decimal.precision.test | model_decimal_precision_test | 1 | 1 | 1 | 1 | |
| 4 | access_discussion | test_new_api_discussion | test_new_api.model_test_new_api_discussion | 1 | 1 | 1 | 1 | |
| 5 | access_message | test_new_api_message | test_new_api.model_test_new_api_message | 1 | 1 | 1 | 1 | |
| 6 | access_emailmessage | test_new_api_emailmessage | test_new_api.model_test_new_api_emailmessage | 1 | 1 | 1 | 1 | |
| 7 | access_multi | test_new_api_multi | test_new_api.model_test_new_api_multi | 1 | 1 | 1 | 1 | |
| 8 | access_multi_line | test_new_api_multi_line | test_new_api.model_test_new_api_multi_line | 1 | 1 | 1 | 1 | |
| 9 | access_multi_line2 | test_new_api_multi_line2 | test_new_api.model_test_new_api_multi_line2 | 1 | 1 | 1 | 1 | |
| 10 | access_multi_tag | test_new_api_multi_tag | test_new_api.model_test_new_api_multi_tag | 1 | 1 | 1 | 1 | |
| 11 | access_creativework_edition | test_new_api_creativework_edition | model_test_new_api_creativework_edition | 1 | 1 | 1 | 1 | |
| 12 | access_creativework_book | test_new_api_creativework_book | model_test_new_api_creativework_book | 1 | 1 | 1 | 1 | |
| 13 | access_creativework_movie | test_new_api_creativework_movie | model_test_new_api_creativework_movie | 1 | 1 | 1 | 1 | |
| 14 | access_mixed | test_new_api_mixed | test_new_api.model_test_new_api_mixed | 1 | 1 | 1 | 1 | |
| 15 | access_domain_bool | access_domain_bool | model_domain_bool | 1 | 1 | 1 | 1 | |
| 16 | access_test_new_api_foo | access_test_new_api_foo | model_test_new_api_foo | 1 | 1 | 1 | 1 | |
| 17 | access_test_new_api_bar | access_test_new_api_bar | model_test_new_api_bar | 1 | 1 | 1 | 1 | |
| 18 | access_test_new_api_related | access_test_new_api_related | model_test_new_api_related | 1 | 1 | 1 | 1 | |
| 19 | access_test_new_api_company | access_test_new_api_company | model_test_new_api_company | 1 | 1 | 1 | 1 | |
| 20 | access_test_new_api_company_attr | access_test_new_api_company_attr | model_test_new_api_company_attr | 1 | 1 | 1 | 1 | |
| 21 | access_test_new_api_compute_inverse | access_test_new_api_compute_inverse | model_test_new_api_compute_inverse | 1 | 1 | 1 | 1 | |
| 22 | access_test_new_api_compute_readonly | access_test_new_api_compute_readonly | model_test_new_api_compute_readonly | 1 | 1 | 1 | 1 | |
| 23 | access_test_new_api_multi_compute_inverse | access_test_new_api_multi_compute_inverse | model_test_new_api_multi_compute_inverse | 1 | 1 | 1 | 1 | |
| 24 | access_test_new_api_recursive | access_test_new_api_recursive | model_test_new_api_recursive | 1 | 1 | 1 | 1 | |
| 25 | access_test_new_api_recursive_tree | access_test_new_api_recursive_tree | model_test_new_api_recursive_tree | 1 | 1 | 1 | 1 | |
| 26 | access_test_new_api_cascade | access_test_new_api_cascade | model_test_new_api_cascade | 1 | 1 | 1 | 1 | |
| 27 | access_test_new_api_compute_readwrite | access_test_new_api_compute_readwrite | model_test_new_api_compute_readwrite | 1 | 1 | 1 | 1 | |
| 28 | access_test_new_api_compute_onchange | access_test_new_api_compute_onchange | model_test_new_api_compute_onchange | 1 | 1 | 1 | 1 | |
| 29 | access_test_new_api_compute_onchange_line | access_test_new_api_compute_onchange_line | model_test_new_api_compute_onchange_line | 1 | 1 | 1 | 1 | |
| 30 | access_test_new_api_compute_dynamic_depends | access_test_new_api_compute_dynamic_depends | model_test_new_api_compute_dynamic_depends | 1 | 1 | 1 | 1 | |
| 31 | access_test_new_api_compute_unassigned | access_test_new_api_compute_unassigned | model_test_new_api_compute_unassigned | 1 | 1 | 1 | 1 | |
| 32 | access_test_new_api_one2many | access_test_new_api_one2many | model_test_new_api_one2many | 1 | 1 | 1 | 1 | |
| 33 | access_test_new_api_one2many_line | access_test_new_api_one2many_line | model_test_new_api_one2many_line | 1 | 1 | 1 | 1 | |
| 34 | access_test_new_api_binary_svg | access_test_new_api_binary_svg | model_test_new_api_binary_svg | 1 | 1 | 1 | 1 | |
| 35 | access_test_new_api_monetary_base | access_test_new_api_monetary_base | model_test_new_api_monetary_base | 1 | 1 | 1 | 1 | |
| 36 | access_test_new_api_monetary_related | access_test_new_api_monetary_related | model_test_new_api_monetary_related | 1 | 1 | 1 | 1 | |
| 37 | access_test_new_api_monetary_custom | access_test_new_api_monetary_custom | model_test_new_api_monetary_custom | 1 | 1 | 1 | 1 | |
| 38 | access_test_new_api_monetary_inherits | access_test_new_api_monetary_inherits | model_test_new_api_monetary_inherits | 1 | 1 | 1 | 1 | |
| 39 | access_test_new_api_field_with_caps | access_test_new_api_field_with_caps | model_test_new_api_field_with_caps | 1 | 1 | 1 | 1 | |
| 40 | access_test_new_api_req_m2o | access_test_new_api_req_m2o | model_test_new_api_req_m2o | 1 | 1 | 1 | 1 | |
| 41 | access_test_new_api_selection | access_test_new_api_selection | model_test_new_api_selection | 1 | 1 | 1 | 1 | |
| 42 | access_test_new_api_attachment | access_test_new_api_attachment | model_test_new_api_attachment | 1 | 1 | 1 | 1 | |
| 43 | access_test_new_api_attachment_host | access_test_new_api_attachment_host | model_test_new_api_attachment_host | 1 | 1 | 1 | 1 | |
| 44 | access_test_new_api_model_image | access_test_new_api_model_image | model_test_new_api_model_image | 1 | 1 | 1 | 1 | |
| 45 | access_test_new_api_model_a | access_test_new_api_model_a | model_test_new_api_model_a | 1 | 1 | 1 | 1 | |
| 46 | access_test_new_api_model_b | access_test_new_api_model_b | model_test_new_api_model_b | 1 | 1 | 1 | 1 | |
| 47 | access_test_new_api_model_parent | access_test_new_api_model_parent | model_test_new_api_model_parent | 1 | 1 | 1 | 1 | |
| 48 | access_test_new_api_model_child | access_test_new_api_model_child | model_test_new_api_model_child | 1 | 1 | 1 | 1 | |
| 49 | access_test_new_api_model_child_nocheck | access_test_new_api_model_child_nocheck | model_test_new_api_model_child_nocheck | 1 | 1 | 1 | 1 | |
| 50 | access_test_new_api_display | access_test_new_api_display | model_test_new_api_display | 1 | 1 | 1 | 1 | |
| 51 | access_test_new_api_model_active_field | access_test_new_api_model_active_field | model_test_new_api_model_active_field | 1 | 1 | 1 | 1 | |
| 52 | access_test_new_api_model_many2one_reference | access_test_new_api_model_many2one_reference | model_test_new_api_model_many2one_reference | 1 | 1 | 1 | 1 | |
| 53 | access_test_new_api_inverse_m2o_ref | access_test_new_api_inverse_m2o_ref | model_test_new_api_inverse_m2o_ref | 1 | 1 | 1 | 1 | |
| 54 | access_test_new_api_model_binary | access_test_new_api_model_binary | model_test_new_api_model_binary | 1 | 1 | 1 | 1 | |
| 55 | access_test_new_api_model_child_m2o | access_test_new_api_model_child_m2o | model_test_new_api_model_child_m2o | 1 | 1 | 1 | 1 | |
| 56 | access_test_new_api_model_parent_m2o | access_test_new_api_model_parent_m2o | model_test_new_api_model_parent_m2o | 1 | 1 | 1 | 1 | |
| 57 | access_test_new_api_model_private_address_onchange | access_test_new_api_model_private_address_onchange | model_test_new_api_model_private_address_onchange | base.group_user | 1 | 1 | 1 | 1 |
| 58 | access_test_new_api_partner | access_test_new_api_partner | test_new_api.model_test_new_api_partner | 1 | 1 | 1 | 1 | |
| 59 | access_test_new_api_req_m2o_transient | access_test_new_api_req_m2o_transient | model_test_new_api_req_m2o_transient | 0 | 0 | 0 | 0 | |
| 60 | access_test_new_api_country | access_test_new_api_country | model_test_new_api_country | base.group_user | 1 | 1 | 1 | 1 |
| 61 | access_test_new_api_city | access_test_new_api_city | model_test_new_api_city | base.group_user | 1 | 1 | 1 | 1 |
| 62 | access_test_new_api_monetary_order | access_test_new_api_monetary_order | model_test_new_api_monetary_order | 1 | 1 | 1 | 1 | |
| 63 | access_test_new_api_monetary_order_line | access_test_new_api_monetary_order_line | model_test_new_api_monetary_order_line | 1 | 1 | 1 | 1 | |
| 64 | access_test_new_api_model_selection_base | access_test_new_api_model_selection_base | model_test_new_api_model_selection_base | 1 | 1 | 1 | 1 | |
| 65 | access_test_new_api_model_selection_required | access_test_new_api_model_selection_required | model_test_new_api_model_selection_required | 1 | 1 | 1 | 1 | |
| 66 | access_test_new_api_model_selection_non_stored | access_test_new_api_model_selection_non_stored | model_test_new_api_model_selection_non_stored | 1 | 1 | 1 | 1 | |
| 67 | access_test_new_api_model_selection_required_for_write_override | access_test_new_api_model_selection_required_for_write_override | model_test_new_api_model_selection_required_for_write_override | 1 | 1 | 1 | 1 | |
| 68 | access_test_new_api_model_selection_related | access_test_new_api_model_selection_related | test_new_api.model_test_new_api_model_selection_related | base.group_user | 1 | 1 | 1 | 1 |
| 69 | access_test_new_api_model_selection_related_updatable | access_test_new_api_model_selection_related_updatable | test_new_api.model_test_new_api_model_selection_related_updatable | base.group_user | 1 | 1 | 1 | 1 |
| 70 | access_test_new_api_move | access_test_new_api_move | model_test_new_api_move | 1 | 1 | 1 | 1 | |
| 71 | access_test_new_api_move_line | access_test_new_api_move_line | model_test_new_api_move_line | 1 | 1 | 1 | 1 | |
| 72 | access_test_new_api_payment | access_test_new_api_payment | model_test_new_api_payment | 1 | 1 | 1 | 1 | |
| 73 | access_test_new_api_order | access_test_new_api_order | model_test_new_api_order | 1 | 1 | 1 | 1 | |
| 74 | access_test_new_api_order_line | access_test_new_api_order_line | model_test_new_api_order_line | 1 | 1 | 1 | 1 | |
| 75 | access_test_new_api_model_shared_cache_compute_parent | access_test_new_api.model_shared_cache_compute_parent | model_test_new_api_model_shared_cache_compute_parent | 1 | 1 | 1 | 1 | |
| 76 | access_test_new_api_model_shared_cache_compute_line | access_test_new_api.model_shared_cache_compute_line | model_test_new_api_model_shared_cache_compute_line | 1 | 1 | 1 | 1 | |
| 77 | access_test_new_api_compute_container | access_test_new_api_compute_container | model_test_new_api_compute_container | 1 | 1 | 1 | 1 | |
| 78 | access_test_new_api_compute_member | access_test_new_api_compute_member | model_test_new_api_compute_member | 1 | 1 | 1 | 1 | |
| 79 | access_test_new_api_user | access_test_new_api_user | model_test_new_api_user | 1 | 1 | 1 | 1 | |
| 80 | access_test_new_api_group | access_test_new_api_group | model_test_new_api_group | 1 | 1 | 1 | 1 | |
| 81 | access_test_new_api_compute_editable | access_test_new_api_compute_editable | model_test_new_api_compute_editable | 1 | 1 | 1 | 1 | |
| 82 | access_test_new_api_compute_editable_line | access_test_new_api_compute_editable_line | model_test_new_api_compute_editable_line | 1 | 1 | 1 | 1 | |
| 83 | access_test_new_api_model_constrained_unlinks | access_test_new_api_model_constrained_unlinks | model_test_new_api_model_constrained_unlinks | 1 | 1 | 1 | 1 | |
| 84 | access_test_new_api_trigger_left | access_test_new_api_trigger_left | model_test_new_api_trigger_left | 1 | 1 | 1 | 1 | |
| 85 | access_test_new_api_trigger_middle | access_test_new_api_trigger_middle | model_test_new_api_trigger_middle | 1 | 1 | 1 | 1 | |
| 86 | access_test_new_api_trigger_right | access_test_new_api_trigger_right | model_test_new_api_trigger_right | 1 | 1 | 1 | 1 | |
| 87 | access_test_new_api_crew | access_test_new_api_crew | model_test_new_api_crew | base.group_user | 1 | 1 | 1 | 1 |
| 88 | access_test_new_api_ship | access_test_new_api_ship | model_test_new_api_ship | base.group_user | 1 | 1 | 1 | 1 |
| 89 | access_test_new_api_pirate | access_test_new_api_pirate | model_test_new_api_pirate | base.group_user | 1 | 1 | 1 | 1 |
| 90 | access_test_new_api_prisoner | access_test_new_api_prisoner | model_test_new_api_prisoner | base.group_user | 1 | 1 | 1 | 1 |
| 91 | access_test_new_api_precompute | access_test_new_api_precompute | model_test_new_api_precompute | 1 | 0 | 0 | 0 | |
| 92 | access_test_new_api_precompute_line | access_test_new_api_precompute_line | model_test_new_api_precompute_line | 1 | 0 | 0 | 0 | |
| 93 | access_test_new_api_precompute_combo | access_test_new_api_precompute_combo | model_test_new_api_precompute_combo | 1 | 0 | 0 | 0 | |
| 94 | access_test_new_api_precompute_editable | access_test_new_api_precompute_editable | model_test_new_api_precompute_editable | 1 | 0 | 0 | 0 | |
| 95 | access_test_new_api_precompute_readonly | access_test_new_api_precompute_readonly | model_test_new_api_precompute_readonly | 1 | 0 | 0 | 0 | |
| 96 | access_test_new_api_precompute_required | access_test_new_api_precompute_required | model_test_new_api_precompute_required | 1 | 0 | 0 | 0 | |
| 97 | access_test_new_api_precompute_monetary | access_test_new_api_precompute_monetary | model_test_new_api_precompute_monetary | 1 | 0 | 0 | 0 | |
| 98 | access_test_new_api_prefetch | access_test_new_api_prefetch | model_test_new_api_prefetch | 1 | 0 | 0 | 0 | |
| 99 | access_test_new_api_modified | access_test_new_api_modified | model_test_new_api_modified | base.group_user | 1 | 1 | 1 | 1 |
| 100 | access_test_new_api_modified_line | access_test_new_api_modified_line | model_test_new_api_modified_line | base.group_user | 1 | 1 | 1 | 1 |
| 101 | access_test_new_api_related_translation_1 | access_test_new_api_related_translation_1 | model_test_new_api_related_translation_1 | 1 | 1 | 1 | 1 | |
| 102 | access_test_new_api_related_translation_2 | access_test_new_api_related_translation_2 | model_test_new_api_related_translation_2 | 1 | 1 | 1 | 1 | |
| 103 | access_test_new_api_related_translation_3 | access_test_new_api_related_translation_3 | model_test_new_api_related_translation_3 | 1 | 1 | 1 | 1 | |
| 104 | access_test_new_api_indexed_translation | access_test_new_api_indexed_translation | model_test_new_api_indexed_translation | 1 | 1 | 1 | 1 | |
| 105 | access_test_new_api_empty_char | access_test_new_api_empty_char | model_test_new_api_empty_char | 1 | 1 | 1 | 1 |