Permissions

Note

This document covers the internals of Wagtail’s permissions system. You should read about how Wagtail makes use of Django’s permissions system first.

Please note that aside from the register_permission_policy() function, the APIs described in this document are considered internal and thus are not subject to our Deprecation policy.

At the basic level, Wagtail’s permission system is implemented using a set of classes called “permission policies” that define the permission rules for a given Django model. Whenever a permission test is performed, a global registry is consulted to determine the permission policy instance to use for a given Django model. As such, any model managed within Wagtail should register a corresponding permission policy instance to the global registry.

Other supporting code (not documented here) is used by pages and snippets to cater for more specific permission checks needed by features such as publishing, locking, and workflows. As a result, the following should not be considered a comprehensive documentation of how Wagtail does permission checks.

Permission policies

class wagtail.permission_policies.BasePermissionPolicy(model)

A ‘permission policy’ is an object that handles all decisions about the actions users are allowed to perform on a given model. The mechanism by which it does this is arbitrary, and may or may not involve the django.contrib.auth Permission model; it could be as simple as “allow all users to do everything”.

In this way, admin apps can change their permission-handling logic just by swapping to a different policy object, rather than having that logic spread across numerous view functions.

BasePermissionPolicy is an abstract class that all permission policies inherit from. The only method that subclasses need to implement is users_with_any_permission(); all other methods can be derived from that (but in practice, subclasses will probably want to override additional methods, either for efficiency or to implement more fine-grained permission logic).

Parameters:

model – The model class that this permission policy applies to. This may be a model class or a string in the form of app_label.model_name.

get_all_permissions_for_user(user)

Return a set of all permissions that the given user has on this model.

They may be instances of Permission, or custom permission objects defined by the policy, which are not necessarily model instances.

get_cached_permissions_for_user(user)

Return a list of all permissions that the given user has on this model, using the cache if available and populating the cache if not.

This can be useful for the other methods to perform efficient queries against the set of permissions that the user has.

user_has_permission(user, action)

Return whether the given user has permission to perform the given action on some or all instances of this model.

user_has_any_permission(user, actions)

Return whether the given user has permission to perform any of the given actions on some or all instances of this model.

users_with_any_permission(actions)

Return a queryset of users who have permission to perform any of the given actions on some or all instances of this model.

users_with_permission(action)

Return a queryset of users who have permission to perform the given action on some or all instances of this model.

user_has_permission_for_instance(user, action, instance)

Return whether the given user has permission to perform the given action on the given model instance.

user_has_any_permission_for_instance(user, actions, instance)

Return whether the given user has permission to perform any of the given actions on the given model instance.

instances_user_has_any_permission_for(user, actions)

Return a queryset of all instances of this model for which the given user has permission to perform any of the given actions.

instances_user_has_permission_for(user, action)

Return a queryset of all instances of this model for which the given user has permission to perform the given action.

users_with_any_permission_for_instance(actions, instance)

Return a queryset of all users who have permission to perform any of the given actions on the given model instance.

users_with_permission_for_instance(action, instance)

Return a queryset of all users who have permission to perform the given action on the given model instance.

class wagtail.permission_policies.BaseDjangoAuthPermissionPolicy(model, auth_model=None)

Extends BasePermissionPolicy with helper methods useful for policies that need to perform lookups against the Permission model.

Parameters:
  • model – The model class that this permission policy applies to. This may be a model class or a string in the form of app_label.model_name.

  • auth_model – The model class (or a string in the form of app_label.model_name) to use for permission record lookups. Usually this will match model (which specifies the type of instances that instances_user_has_permission_for() will return), but this may differ when swappable models are in use - for example, an interface for editing user records might use a custom User model but will typically still refer to the permission records for auth.User.

class wagtail.permission_policies.ModelPermissionPolicy(model, auth_model=None)

A permission policy that enforces permissions at the model level, by consulting the standard Permission model directly.

class wagtail.permission_policies.OwnershipPermissionPolicy(model, auth_model=None, owner_field_name='owner')

A permission policy for objects that support a concept of ‘ownership’, where the owner is typically the user who created the object.

This policy piggybacks off add and change permissions defined through the Permission model, as follows:

  • any user with add permission can create instances, and ALSO edit instances that they own

  • any user with change permission can edit instances regardless of ownership

  • ability to edit also implies ability to delete

Besides add, change and delete, no other actions are recognised or permitted (unless the user is an active superuser, in which case they can do everything).

class wagtail.permission_policies.collections.CollectionPermissionPolicy(model, auth_model=None)

A permission policy for objects that are assigned locations in the Collection tree. Permissions may be defined at any node of the hierarchy, through the GroupCollectionPermission model, and propagate downwards. These permissions are applied to objects according to the standard Permission model.

class wagtail.permission_policies.collections.CollectionOwnershipPermissionPolicy(model, auth_model=None, owner_field_name='owner')

A permission policy for objects that are assigned locations in the Collection tree. Permissions may be defined at any node of the hierarchy, through the GroupCollectionPermission model, and propagate downwards. These permissions are applied to objects according to the ‘ownership’ permission model (see OwnershipPermissionPolicy).

class wagtail.permission_policies.collections.CollectionManagementPermissionPolicy(model, auth_model=None)

A permission policy for managing collections themselves, rather than objects assigned to collections.

class wagtail.permission_policies.pages.PagePermissionPolicy(model=None)

A permission policy for page objects, which are arranged in a tree structure. Permissions may be defined at any node of the tree, through the GroupPagePermission model, and propagate downwards. These permissions are applied to objects according to the ‘ownership’ permission model (see OwnershipPermissionPolicy).

class wagtail.permission_policies.sites.SitePermissionPolicy(model, auth_model=None, site_field_name='site')

A permission policy for objects that are associated with site records, such as wagtail.contrib.settings.models.BaseSiteSetting subclasses (see Settings models). Permissions may be assigned globally through standard Permission objects, or for individual sites through wagtail.models.GroupSitePermission records.

Permission policy registry

class wagtail.permissions.PolicyRegistry

A registry that maps model classes to their permission policy instances. This is used by Wagtail to determine which permission policy to use for a given model class.

Instead of using this class directly, use the global policy_registry instance and the register_permission_policy() function instead.

get_by_type(cls: type[Model], fallback=True) BasePermissionPolicy

Get the permission policy for a given model class. If a matching policy was registered with exact_class=True, it will be returned. Otherwise, the policy registered with exact_class=False for the given class or its nearest ancestor class will be returned. If no policy can be found and fallback is True, a default fallback ModelPermissionPolicy will be used. Otherwise, return None.

get(obj: Model) BasePermissionPolicy

Get the permission policy for a given model instance based on its class.

wagtail.permissions.policy_registry = <wagtail.permissions.PolicyRegistry object>

A global instance of PolicyRegistry used to register and look up permission policies for models managed by Wagtail.

Retrieving a permission policy for a given Django model class or instance can be done as below.

from wagtail.permissions import policy_registry
from .models import MyModel

# With the model class
policy_registry.get_by_type(MyModel)
# With a model instance
policy_registry.get(MyModel.objects.first())
wagtail.permissions.register_permission_policy(model: type[Model], policy: BasePermissionPolicy = None, exact_class=False)

Register a permission policy for a given model class.

If no policy is provided, a default ModelPermissionPolicy will be created. If exact_class is set to True, the policy will only be used for the exact model class, otherwise it will also be used for subclasses of the model class.

To register a permission policy for a model, call this function at the top of the model app’s wagtail_hooks.py.

# wagtail_hooks.py
from wagtail.permissions import register_permission_policy
from .models import MyModel


register_permission_policy(MyModel)
...  # More customizations

Alternatively, you can also call the function from the AppConfig.ready() method.

# apps.py
class MyAppConfig(AppConfig):
    ...

    def ready(self):
        from wagtail.permissions import register_permission_policy
        from .models import MyModel

        register_permission_policy(MyModel)

Note

Currently, register_permission_policy(MyModel) is the only officially supported use case of this function.

While it is possible to register a custom permission policy instance for any model (including Wagtail’s built-in models), we cannot guarantee that a custom permissions implementation would always be respected by Wagtail. We intend to support this in the future. Refer to our issue tracker for supporting custom permission behavior for more details.