- Author:
- asfaltboy
- Posted:
- September 3, 2015
- Language:
- Python
- Version:
- 1.4
- Score:
- 1 (after 1 ratings)
How to use
Use this admin filter together with a numeric field to allow filtering changlist by field values range (in this case, age groups):
For example, to group customers by age groups:
class Customer(models.Model):
# ...
age = models.IntegerField()
age.list_lookup_range = (
(None, _('All')),
([0, 2], '0-2'),
([2, 4], '2-4'),
([4, 18], '4-18'),
([18, 65], '18-65'),
([65, None], '65+'),
))
class CustomerAdmin(admin.ModelAdmin):
list_filter = [('age', ValueRangeFilter), ]
Inspiration
This snippet (for django < 1.4) inspired me to make this work for newer django versions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | from django.contrib import admin
from django.utils.translation import ugettext_lazy as _
class ValueRangeFilter(admin.FieldListFilter):
def __init__(self, field, *args, **kwargs):
self.lookup_kwarg = '%s__range' % kwargs['field_path']
self.lookup_choices = getattr(field, 'lookup_range', (
# default range options
(None, _('All')),
([0, 100], '0-100'),
([100, 300], '100-300'),
([300, 1000], '300-1000'),
([1000, 10000], '1000-10000'),
([10000, None], '10000+'),
))
super(ValueRangeFilter, self).__init__(field, *args, **kwargs)
def expected_parameters(self):
return [self.lookup_kwarg]
def get_value_range(self):
if not self.used_parameters.get(self.lookup_kwarg):
return None
return [int(n.strip("' ")) if n.strip("' ") != 'None' else None
for n in self.used_parameters[self.lookup_kwarg].strip(
'[]').split(',')]
def choices(self, cl):
for lookup, title in self.lookup_choices:
yield {
'selected': self.get_value_range() == lookup,
'query_string': cl.get_query_string({
self.lookup_kwarg: lookup,
}, []),
'display': title,
}
def queryset(self, request, queryset):
if not self.used_parameters:
return queryset
values_range = self.get_value_range()
if not values_range:
return queryset
min_val, max_val = values_range
if min_val and max_val:
query = {'%s__range' % self.field_path:
(min_val, max_val)}
elif min_val:
query = {'%s__gt' % self.field_path: min_val}
elif max_val:
query = {'%s__lt' % self.field_path: max_val}
else:
query = {}
return queryset.filter(**query)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
Works fine, very nice. In your example you are using the wrong attribute name ("list_lookup_range" instead" of "lookup_range").
Cheers Roland
#
Please login first before commenting.