Reputation: 1488
I am developing an application which has both admins and sub-admins. Sub-admins are created based on the group they belong to. So a sub-admin can see only data which is related to his group. This functionality is working perfectly.
Now, I want to create a filter option based on users. For super-admin it works fine but when I see from sub-admin, I can see the complete list of users in the filter list. How can I limit this list based on sub-admins users.
Suppose there is a total of 20 users, and sub-admin has only 3 users in his group. So I am able to see only 3 in the list view but in the filter option I can see all 20. Can I limit this filter to only those 3 users only?
My admin model looks like below:
class VideoDetailsAdmin(admin.ModelAdmin):
list_display = ('video_id', 'user', 'status', 'description', 'video_name', 'upload_time', 'duration')
list_filter = ('user', )
def get_queryset(self, request):
# Get the groups of logged in user
query_set = Group.objects.filter(user = request.user)
group_list = []
for g in query_set:
group_list.append(g.name)
# Get the user ids of Users in those groups
id_list = []
for user in list(User.objects.filter(groups__name__in=group_list)):
id_list.append(user.id)
# Create unique users list
users = list(set(id_list))
# Override the get_queryset method for Admin
qs = super(VideoDetailsAdmin, self).get_queryset(request)
if not request.user.is_superuser:
return qs.filter(user__in = users)
else:
return qs
I've seen few resources available on Django documentation, but I am wondering what could be the best approach to solve this problem. Is there a way I can re-use the get_queryset() code
Django Version: 2.1
EDIT 1:
Made following modifications but no filter is visible.
# Filter list
class UserFilterList(admin.SimpleListFilter):
# Human readable title, which is displayed on the right sidebar
title = ("User")
# Parameter for the filter that will be used in the URL query
parameter_name = "user"
def lookups(self, request, model_admin):
# To get user's groups
query_set = Group.objects.filter(user = request.user)
group_list = []
for g in query_set:
group_list.append(g.name)
# To get all users associated in those groups
id_list = []
for user in list(User.objects.filter(groups__name__in=group_list)):
id_list.append(user.id)
users = list(set(id_list))
qs = model_admin.get_queryset(request)
def queryset(self, request, queryset):
if not request.user.is_superuser:
return qs.filter(user__in = users)
else:
return qs
EDIT 2:
class UserFilterList(SimpleListFilter):
title = "user"
parameter_name = "user"
def lookups(self, request, model_admin):
visible_users = model_admin.get_visible_users(request)
print(visible_users[0])
return ((user, user) for user in visible_users)
def queryset(self, request, queryset):
return self.value()
FINAL WORKING SOLUTION (THANKS TO @dirkgroten):
class UserFilterList(SimpleListFilter):
title = "user"
parameter_name = "user"
def lookups(self, request, model_admin):
if not request.user.is_superuser:
visible_users = model_admin.get_visible_users(request)
# Sub user - return same group users
return ((user.id, user) for user in visible_users)
else:
# Superuser - return all users
return ((user.id, user) for user in User.objects.filter())
def queryset(self, request, queryset):
return queryset.filter(user=self.value()) if self.value() else queryset
class VideoDetailsAdmin(admin.ModelAdmin):
list_display = ('video_id', 'user', 'status', 'description', 'video_name', 'upload_time', 'duration')
list_filter = (UserFilterList, )
def get_visible_users(self, request):
# Get the groups of logged in user
query_set = Group.objects.filter(user = request.user)
group_list = []
for g in query_set:
group_list.append(g.name)
return User.objects.filter(groups__name__in=group_list)
def get_queryset(self, request):
users = self.get_visible_users(request)
# Override the get_queryset method for Admin
qs = super(VideoDetailsAdmin, self).get_queryset(request)
if not request.user.is_superuser:
return qs.filter(user__in = users)
else:
return qs
Upvotes: 2
Views: 4928
Reputation: 20702
Don't change your VideoDetailsAdmin
, only use a custom list filter:
class VideoDetailsAdmin(ModelAdmin):
list_filter = UserFilterList # that's the only line to change
def get_visible_users(self, request): # small refactor to re-use in filter
query_set = Group.objects.filter(user=request.user)
group_list = []
for g in query_set:
group_list.append(g.name)
# To get all users associated in those groups
return User.objects.filter(groups__name__in=group_list)
def get_queryset(self, request):
users = self.get_visible_users(request)
# Override the get_queryset method for Admin
qs = super(VideoDetailsAdmin, self).get_queryset(request)
if not request.user.is_superuser:
return qs.filter(user__in=users)
else:
return qs
class UserFilterList(SimpleListFilter):
def lookups(self, request, model_admin):
visible_users = model_admin.get_visible_users(request)
return ((user.pk, user.username) for user in visible_users)
def queryset(self, request, queryset):
return queryset.filter(user_id=self.value()) if self.value() else queryset
Upvotes: 2