I have a Django app with multiple levels of admin role and users defined by the django-role-permissions package. I want to apply permissions to users only through groups, defining the permissions for the group roles and assigning the user to the correct group.
I want to "hide" the higher level admin roles in Groups when lower level admins create users. A lower level admin should not be able assign a created user to a higher level admin role in Groups.
I can do this with Users (lower level admins cannot view / change higher level admins) by overriding get_queryset with code shown below. I want to be able to do something equivalent with the roles in Groups. I would prefer to do this in my admin.py rather than in templates. It would have been nice if the Groups members were also gathered by get_queryset, but that does not seem to be the case. I have searched around without finding anything definitive. I set up django-debug-toolbar to see the context passed into the forms, but I don't see the Groups elements passed in that way to change_form. It's tempting to try overriding FilteredSelectMultiple inside of django.contrib.admin.widgets, but I don't yet see exactly where the Groups elements are actually gathered, so that feels like too much guesswork to try that yet.
What would be the best way for me to proceed?
from django.contrib.auth.models import User
from django.contrib import admin
from django.utils.translation import ugettext, ugettext_lazy as _
from rolepermissions.checkers import has_role
from myapp.roles import SuperAdmin, Admin # can't import TrustedUser and User because already have User above LOL
import logging
logger = logging.getLogger(__name__)
class MyUserAdmin(UserAdmin):
def get_queryset(self, request):
qs = super(MyUserAdmin, self).get_queryset(request)
logger.debug(f'get_queryset logged in user is {request.user}, queryset is {qs}')
if request.user.is_superuser: # see all users
return qs
elif has_role(request.user, SuperAdmin): # see all but superusers
return qs.filter(is_superuser=False)
elif has_role(request.user, Admin): # see all but superusers & SuperAdmins
excludes = [x.username for x in qs if has_role(x, SuperAdmin)] # has_role will be true for superuser
return qs.exclude(username__in=excludes)
else:
logger.debug(f'get_queryset should never get here {request.user}, acting on qs {qs}')
return q.none()
#Unregister current Django Admin
admin.site.unregister(User)
#Register current Django Admin
admin.site.register(User, MyUserAdmin)
By looking at the admin feature with the web developer tools, the objects I care about a the RelatedFieldWidgetWrapper which contains the FilteredSelectMultiple class. Going through all the inheritance, eventually I got to forms/widget, and within forms/widget there is a method optgroups that appears to provide the group lookup that I am looking for.
So I do want to override FilteredSelectMultiple. How can I do that or how can I override django.contrib.admin.widgets?