I am trying to set up object-level permissions using Django guardian and groups; where I give permissions to the groups - not the users - and add/remove users from the groups as required.
When a user has permission to interact with an object instance - because they are in a group that has the necessary permissions - how can I determine which of the user's groups gave them the permission?
As an example, building off the example in the django-guardian-docs , ideally there would be something like:
>>> joe.has_perm_from_groups('sites.change_site', site)
[site_owners_group]
Django guardian has a shortcut called get_groups_with_perms(obj)
that Returns queryset of all Group objects with any object permissions for the given obj
. https://django-guardian.readthedocs.io/en/stable/api/guardian.shortcuts.html#get-groups-with-perms
Django has a queryset method called intersection
that returns the shared elements of two or more QuerySets
https://docs.djangoproject.com/en/3.2/ref/models/querysets/#intersection
Using these two functions, I can find the groups that the user is in that also have permissions for the object. I then use a for loop to identify the group with the permission. If two groups have the permission, I don't know how I would work out which one gave the user the permission, so the first group found is returned.
# Find the union of groups
groups = user.groups.all().intersection(get_groups_with_perms(obj))
# Check if any group has the permission, and return if True
for group in groups:
if 'change_site' in get_perms(group, obj):
return group
return None