djangodjango-admindjango-querysetchangelist

How to filter queryset in changelist_view in django admin?


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?


Solution

  • 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/