How to grant object permissions on a polymorphic model#
A permission declared on a polymorphic base is stored under the base’s content type, so django-guardian’s own functions miss it when you give them a subclass instance. Use FairDM’s helpers when your portal’s code grants, removes, lists or looks up a stored permission on an organization or on a polymorphic model of your own.
Before you start#
The helpers cover models that name their polymorphic base with
type_of.Contributordoes, so its subclassesPersonandOrganizationare covered. A model of your own is covered when it declarestype_ofin the same way.Do not use them to give a person access to a project, dataset, sample or measurement. A permission stored for one of those four grants nothing. List the person as a contributor at the level they need instead. See How access to a record is decided and Contribution levels and record access.
Do not grant
manage_organization. A person holds it through a current owner affiliation and no stored row is honoured.
Steps#
Import the helpers from
fairdm.core.utilsrather than fromguardian.shortcuts:from fairdm.core.utils import ( assign_perm, get_objects_for_user, get_perms, remove_perm, )
Grant the permission to a person or a group. The permission is declared on
Contributor, so it is stored against the base record even though you pass anOrganization:assign_perm("change_contributor", user, organization)
Check it with Django’s usual call. Name the permission with its app label:
user.has_perm("contributors.change_contributor", organization)
List what a person or group holds on the record. The result merges rows stored against the subclass and against its base, and is sorted:
permissions = get_perms(user, organization)
Find the records a person holds a permission for. Name the permission after the subclass, here
change_organization. The helper works out the base permission,change_contributor, and narrows your queryset by it:from fairdm.contrib.contributors.models import Organization organizations = get_objects_for_user( user, "contributors.change_organization", Organization )
Take the permission away:
remove_perm("change_contributor", user, organization)
The result#
The permission is stored once, under the base’s content type, and every call above reads and writes the same row. A call with guardian’s own function would instead file the grant under Organization’s content type, where the permission declared on the base is never looked for.
The helpers retarget a record to its base only when the base declares the permission. A plain record that is not polymorphic, and a subclass permission such as change_organization, which the subclass owns, pass through unchanged.