Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Every user who'll need access to the admin must have the <code>is_staff=True</code> flag. It's <em>never</em> a good idea to allow users not associated with your organization access to the admin. Seriously, just don't do it. If that's your plan, find another.</p> <p>That said, it can be done, but it's not for the faint of heart. There's a lot involved. First subclass the default <code>UserCreationForm</code> and <code>UserChangeForm</code> (Auth uses two separate forms for it's admin). Override the <code>__init__</code> method of each to pull out the <code>request</code> from <code>kwargs</code> (Forms don't get the request by default, but it's necessary here, so you have to do a bit of a workaround.) Then, subclass the default <code>UserAdmin</code>, set <code>form</code> and <code>add_form</code> to the new forms and override <code>get_form</code> (to pass in <code>request</code>) and each of the <code>has_foo_permission</code> methods to limit access. The <code>queryset</code> method also needs to be overrode so users only see users they can modify in the admin.</p> <pre><code>from django.contrib.auth.admin import UserAdmin from django.contrib.auth.forms import UserCreationForm, UserChangeForm from django.contrib.auth.models import Group, Permission class CustomUserCreationForm(UserCreationForm): class Meta(UserCreationForm.Meta): pass def __init__(self, *args, **kwargs): self.request = kwargs.pop('request', None) super(CustomUserCreationForm, self).__init__(*args, **kwargs) # Limit groups and permissions to those that belong to current user if self.request and not self.request.user.is_superuser: self.fields['groups'].queryset = self.request.user.groups.all() self.fields['user_permissions'].queryset = self.request.user.user_permissions.all() class CustomUserChangeForm(UserChangeForm): class Meta(UserChangeForm.Meta): pass def __init__(self, *args, **kwargs): self.request = kwargs.pop('request', None) super(CustomUserChangeForm, self).__init__(*args, **kwargs) # Limit groups and permissions to those that belong to current user if self.request and not self.request.user.is_superuser: self.fields['groups'].queryset = self.request.user.groups.all() self.fields['user_permissions'].queryset = self.request.user.user_permissions.all() class CustomUserAdmin(UserAdmin): form = UserChangeForm add_form = UserCreationForm limited_fieldsets = ( # Copied from default `UserAdmin`, but removed `is_superuser` (None, {'fields': ('username', 'password')}), (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}), (_('Permissions'), {'fields': ('is_active', 'is_staff', 'user_permissions')}), (_('Important dates'), {'fields': ('last_login', 'date_joined')}), (_('Groups'), {'fields': ('groups',)}), ) def get_fieldsets(self, request, obj=None): if not obj: return self.add_fieldsets elif not request.user.is_superuser: return self.limited_fieldsets else: return super(CustomUserAdmin, self).get_fieldsets(request, obj) def get_form(self, request, obj=None, **kwargs): """Return a metaclass that will automatically pass `request` kwarg into the form""" ModelForm = super(LinkAdmin, self).get_form(request, obj, **kwargs) class ModelFormMetaClass(ModelForm): def __new__(cls, *args, **kwargs): kwargs['request'] = request return ModelForm(*args, **kwargs) return ModelFormMetaClass def has_add_permission(self, request): """ If not superuser only allow add if the current user has at least some groups or permissions. (they'll have to be able to at least have something to assign the user they are creating). """ if not request.user.is_superuser: if not request.user.groups.exists() or not request.user.user_permissions.exist(): return False return True def has_change_permission(self, request, obj=None): """ If not superuser, current user can only modify users who have a subset of the groups and permissions they have. """ if obj and not request.user.is_superuser: # Check that all of the object's groups are in the current user's groups user_groups = list(request.user.groups.all()) for group in obj.groups.all(): try: user_groups.index(group) except ValueError: return False # Check that all of the object's permissions are in the current user's permissions user_permissions = list(request.user.user_permissions.all()) for permission in obj.user_permissions.all(): try: user_permissions.index(permission) except ValueError: return False return True def has_delete_permission(self, request, obj=None): """Same logic as `has_change_permission`""" return self.has_change_permission(request, obj) def queryset(self, request): qs = super(CustomUserAdmin, self).queryset(self, request) if request.user.is_superuser: return qs else: """ This part is a little counter-intuitive. We're going to first get a list of all groups/permissions that don't belong to the user, and then use that to exclude users that do have those from the queryset. """ user_group_pks = [g.pk for g request.user.groups.values('pk')] exclude_groups = Group.objects.exclude(pk__in=user_group_pks) user_permission_pks = [p.pk for p in request.user.user_permissions.values('pk')] exclude_permissions = Permission.objects.exclude(pk__in=user_permission_pks) return qs.exclude(groups__in=exclude_groups, user_permissions__in=exclude_permissions) admin.site.unregister(User) admin.site.register(User, CustomUserAdmin) </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload