The user delivers goods to some countries for free. I wanted to filter out these countries:
All - all countries, Yes - free scheduled delivery, No - paid postage.
The main answer for this question did not work for me (Django 1.3). I think because __init__ did not have a field_path parameter. It is also subclassed by DateFieldFilterSpec . postage field is FloatField
from django.contrib.admin.filterspecs import FilterSpec class IsFreePostage(FilterSpec): def __init__(self, f, request, params, model, model_admin, field_path=None): super(IsFreePostage, self).__init__(f, request, params, model, model_admin, field_path) self.removes = { 'Yes': ['postage__gt'], 'No': ['postage__exact'], 'All': ['postage__exact', 'postage__gt'] } self.links = ( ('All', {}), ('Yes', {'postage__exact': 0}), ('No', {'postage__gt': 0})) if request.GET.has_key('postage__exact'): self.ttl = 'Yes' elif request.GET.has_key('postage__gt'): self.ttl = 'No' else: self.ttl = 'All' def choices(self, cl): for title, param_dict in self.links: yield {'selected': title == self.ttl, 'query_string': cl.get_query_string(param_dict, self.removes[title]), 'display': title} def title(self): return 'Free Postage' FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'free_postage', False), IsFreePostage))
At self.links we supply dicts. used to build HTTP request strings, such as ?postage__exact=0 for each of the possible filters. Filters, I think, are cumulative, therefore, if there was a previous request “No”, and now we have a request “Yes”, we must delete the Request “No”. self.removes indicates what needs to be removed for each request. The choices method constructs query strings, indicates which filter was selected, and sets the display name of the filter.