Default filter in Django admin
In order to achieve this and have a usable 'All' link in your sidebar (ie one that shows all rather than showing pending), you'd need to create a custom list filter, inheriting from django.contrib.admin.filters.SimpleListFilter
and filtering on 'pending' by default. Something along these lines should work:
from datetime import date
from django.utils.translation import ugettext_lazy as _
from django.contrib.admin import SimpleListFilter
class StatusFilter(SimpleListFilter):
title = _('Status')
parameter_name = 'status'
def lookups(self, request, model_admin):
return (
(None, _('Pending')),
('activate', _('Activate')),
('rejected', _('Rejected')),
('all', _('All')),
)
def choices(self, cl):
for lookup, title in self.lookup_choices:
yield {
'selected': self.value() == lookup,
'query_string': cl.get_query_string({
self.parameter_name: lookup,
}, []),
'display': title,
}
def queryset(self, request, queryset):
if self.value() in ('activate', 'rejected'):
return queryset.filter(status=self.value())
elif self.value() == None:
return queryset.filter(status='pending')
class Admin(admin.ModelAdmin):
list_filter = [StatusFilter]
EDIT: Requires Django 1.4 (thanks Simon)
I know this question is quite old now, but it's still valid. I believe this is the most correct way of doing this. It's essentially the same as Greg's method, but formulated as an extendible class for easy re-use.
from django.contrib.admin import SimpleListFilter
from django.utils.encoding import force_text
from django.utils.translation import ugettext as _
class DefaultListFilter(SimpleListFilter):
all_value = '_all'
def default_value(self):
raise NotImplementedError()
def queryset(self, request, queryset):
if self.parameter_name in request.GET and request.GET[self.parameter_name] == self.all_value:
return queryset
if self.parameter_name in request.GET:
return queryset.filter(**{self.parameter_name:request.GET[self.parameter_name]})
return queryset.filter(**{self.parameter_name:self.default_value()})
def choices(self, cl):
yield {
'selected': self.value() == self.all_value,
'query_string': cl.get_query_string({self.parameter_name: self.all_value}, []),
'display': _('All'),
}
for lookup, title in self.lookup_choices:
yield {
'selected': self.value() == force_text(lookup) or (self.value() == None and force_text(self.default_value()) == force_text(lookup)),
'query_string': cl.get_query_string({
self.parameter_name: lookup,
}, []),
'display': title,
}
class StatusFilter(DefaultListFilter):
title = _('Status ')
parameter_name = 'status__exact'
def lookups(self, request, model_admin):
return ((0,'activate'), (1,'pending'), (2,'rejected'))
def default_value(self):
return 1
class MyModelAdmin(admin.ModelAdmin):
list_filter = (StatusFilter,)
Took ha22109's answer above and modified to allow the selection of "All" by comparing HTTP_REFERER
and PATH_INFO
.
class MyModelAdmin(admin.ModelAdmin):
def changelist_view(self, request, extra_context=None):
test = request.META['HTTP_REFERER'].split(request.META['PATH_INFO'])
if test[-1] and not test[-1].startswith('?'):
if not request.GET.has_key('decommissioned__exact'):
q = request.GET.copy()
q['decommissioned__exact'] = 'N'
request.GET = q
request.META['QUERY_STRING'] = request.GET.urlencode()
return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)
class MyModelAdmin(admin.ModelAdmin):
def changelist_view(self, request, extra_context=None):
if not request.GET.has_key('decommissioned__exact'):
q = request.GET.copy()
q['decommissioned__exact'] = 'N'
request.GET = q
request.META['QUERY_STRING'] = request.GET.urlencode()
return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)