[16.0][FIX] project_hr: Slowdown when entering the task tree view#1655
[16.0][FIX] project_hr: Slowdown when entering the task tree view#1655
Conversation
|
Hi @pedrobaeza, |
luisDIXMIT
left a comment
There was a problem hiding this comment.
Pre-commit is failing, maybe because you didn’t run it previously. Run it locally to fix the formatting and push it again.
alexey-pelykh
left a comment
There was a problem hiding this comment.
Good optimization idea — batching the search instead of one per record is the right approach for computed fields.
Pre-commit is currently failing though, so that needs a pass before this can move forward. Also, the early return when all_category_ids is empty sets the field on the full recordset, which is fine, but you might also want to handle the case where a task has hr_category_ids populated but company_id is falsy (edge case).
| user_obj = self.env["res.users"] | ||
| all_category_ids = self.mapped('hr_category_ids').ids | ||
| all_company_ids = self.mapped('company_id').ids | ||
| if not all_category_ids: |
There was a problem hiding this comment.
When all_category_ids is empty, you set self.allowed_assigned_user_ids = False and return early. But you should still iterate the tasks to handle the else branch individually — a task might have no categories but another in the batch might. Actually, looking again, if all_category_ids is empty it means NO task in self has categories, so the early return is correct. Disregard this, the logic is fine.
alexey-pelykh
left a comment
There was a problem hiding this comment.
Review: Performance optimization for _compute_allowed_assigned_user_ids
Good approach -- replacing N individual search() calls with a single batched search + in-memory filtering is the right pattern for Odoo computed fields. The performance improvement should be significant when computing across many tasks.
However, there is a behavioral regression and some issues to address before this can be merged.
Behavioral Regression (blocking)
In the original code, when a task has no hr_category_ids, the domain is [] and user_obj.search([]) returns all users -- meaning allowed_assigned_user_ids is populated with every user. In the new code, the else branch sets task.allowed_assigned_user_ids = False (empty recordset). This changes the behavior: tasks without HR categories would show no allowed users instead of all users, potentially breaking the UI for task assignment.
Please restore the original behavior for the no-categories case:
else:
task.allowed_assigned_user_ids = self.env["res.users"].search([])Or, better yet, cache that full user list outside the loop so it is only fetched once.
Pre-commit failure (blocking)
CI shows pre-commit is still failing. Please run pre-commit run --all-files locally and push the fixes.
Minor: string quoting style
The new code uses single quotes ('hr_category_ids', 'company_id') while the rest of the file uses double quotes. OCA convention and the existing code style in this file use double quotes -- please align for consistency.
Suggestion: consider performance of filtered() lambda
The filtered() lambda iterates u.employee_ids.category_ids and u.employee_ids for every user in all_users for every task. If the number of users is large, this could still be slow. Consider building a mapping dict (user -> set of (company_id, category_ids)) before the loop for O(1) lookups per task-user pair.
Overall, the optimization direction is correct. Please fix the behavioral regression and pre-commit issues.
Review posted via CorporateHub OCA review campaign
| task.allowed_assigned_user_ids = user_obj.search(domain) | ||
| task.allowed_assigned_user_ids = all_users.filtered( | ||
| lambda u: any(cat in task.hr_category_ids for cat in u.employee_ids.category_ids) | ||
| and any(emp.company_id == task.company_id for emp in u.employee_ids) |
There was a problem hiding this comment.
Behavioral regression: When task.hr_category_ids is falsy, the original code ran user_obj.search([]) which returns all users. Setting False here changes the behavior -- tasks without HR categories would show no allowed users instead of all users.
Please restore:
else:
task.allowed_assigned_user_ids = self.env["res.users"].search([])Or cache the full user list outside the loop to avoid a per-task search.
| @api.depends("hr_category_ids", "company_id") | ||
| def _compute_allowed_assigned_user_ids(self): | ||
| user_obj = self.env["res.users"] | ||
| all_category_ids = self.mapped('hr_category_ids').ids |
There was a problem hiding this comment.
Minor: single quotes here ('hr_category_ids') while the rest of the file uses double quotes. Please use double quotes for consistency with OCA style conventions.
| all_category_ids = self.mapped('hr_category_ids').ids | |
| all_category_ids = self.mapped("hr_category_ids").ids | |
| all_company_ids = self.mapped("company_id").ids |
Odoo 16
When we have many projects, and each project has many tasks, accessing the task tree view from a project slows down the loading process.
This request corrects the calculation of the allowed_assigned_user_ids field so that it only performs one database access and uses filtering during task iteration.