Skip to content

feat: Performant permission calculation for pages #7943

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

Merged
merged 12 commits into from
Jul 10, 2024

Conversation

fsbraun
Copy link
Member

@fsbraun fsbraun commented Jun 25, 2024

Description

With permissions by page activated, the CMS needs to traverse the page tree to find permissions which apply to a specific page. For each permission, django CMS calculates the list of page IDs it applies to. This calculation is cached.

For projects with large numbers of pages (>> 1,000) these calculations generate long lists of IDs and even using the cached calculations impacts responsiveness.

This PR noticeably improves the responsiveness when working with large page trees.

This PR optimizes the calculation of permission based on a page's path (actually a tuple grant_on and path, where the grant_on code defines if the permission applies to the page itself, its direct children, and/or all of its descendants). This makes both calculating the permissions and evaluating the cached permissions from O(n) to O(1) (n being the number of pages) (but stays O(m) for m being the number of permissions granted).

Thanks to @jrief for testing.
@Aiden-RC Please be invited to test and comment!

Thanks to @vinitkumar for testing a backport to django CMS 3.11.

Deprecations

This PR deprecates some (not officially documented) utility functions in cms.utils.page.permissions which are replaced by their counterparts getting the permission tuples, e.g., get_add_perm_tuples:

  • get_add_ids
  • get_change_ids
  • get_change_advanced_settings_ids
  • get_change_permissions_ids
  • get_delete_ids
  • get_move_page_ids
  • get_publish_ids
  • get_view_ids

It also deprecates the get_page_ids method of the cms.models.PagePermissions model.

Their database access is not efficient and redundant.

Related resources

Checklist

  • I have opened this pull request against develop-4
  • I have added or modified the tests when changing logic
  • I have followed the conventional commits guidelines to add meaningful information into the changelog
  • I have read the contribution guidelines and I have joined the channel #pr-reviews on our Discord Server to find a “pr review buddy” who is going to review my pull request.

@fsbraun fsbraun requested a review from a team June 26, 2024 11:47
Copy link
Contributor

@jrief jrief left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our team experienced a notifiable performance gain after applying this patch.

There haven't been any unexpected side effects.

@fsbraun fsbraun merged commit 8630db8 into django-cms:develop-4 Jul 10, 2024
32 checks passed
fsbraun added a commit that referenced this pull request Jul 10, 2024
* Feat: Calculating page permissions does not require evaluating the full page tree

* Fix N+1 issue, cache all calculated permissions

* Deprecate `cms.utils.permissions.has_page_permission` in favor of `cms.utils.page_permissions.has_generic_permission`

* Deprecate `.get_page_ids` since it is less efficient

* Fix: get_draft_placholders

* Fix: Delete permissions

* Add compatibility shims with deprecation warning

* Fix ruff issue
@fsbraun fsbraun deleted the feat/permission_performance branch January 10, 2025 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

2 participants