How to filter queryset in changelist_view in django admin?

minder picture minder · Apr 12, 2010 · Viewed 9.6k times · Source

Let's say I have a site where Users can add Entries through admin panel. Each User has his own Category he is responsible for (each Category has an Editor assigned through ForeingKey/ManyToManyField).

When User adds Entry, I limit the choices by using EntryAdmin like this:

class EntryAdmin(admin.ModelAdmin):
    (...)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'category':
            if request.user.is_superuser:
                kwargs['queryset'] = Category.objects.all()
            else:
                kwargs['queryset'] = Category.objects.filter(editors=request.user)
            return db_field.formfield(**kwargs)
        return super(EntryAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

This way I can limit the categories to which a User can add Entry and it works perfect.

Now the tricky part: On the Entry changelist/action page I want to show only those Entries which belong to current User's Category. I tried to do this using this method:

    def changelist_view(self, request, extra_context=None):
        if not request.user.is_superuser:
            self.queryset = self.queryset.filter(editors=request.user)

But I get this error:

AttributeError: 'function' object has no attribute 'filter'

This is strange, because I thought it should be a typical QuerySet. Basically such methods are not well documented and digging through tons of Django code is not my favourite sport.

Any ideas how can I achieve my goal?

Answer

Alasdair picture Alasdair · Apr 12, 2010

Warning: This answer is from 2010, and is not useful for Django >= 1.8.

queryset is a method on ModelAdmin which returns a queryset. You need to override it on your EntryAdmin class.

def queryset(self, request):
    qs = super(EntryAdmin, self).queryset(request)
    if request.user.is_superuser:
        return qs
    else:
        return qs.filter(editors=request.user)

Changing the queryset will limit the Entries shown in the list view. You also need to override has_change_permission to ensure that the user has permission to edit the object on the individual object editing page. See the following blog post by James Bennett for further details:

http://www.b-list.org/weblog/2008/dec/24/admin/