Login

Closure for FieldListFilter classes with custom sets of ranges

Author:
ssokolow
Posted:
June 24, 2012
Language:
Python
Version:
1.4
Tags:
filter django admin fieldlistfilter
Score:
0 (after 0 ratings)

This closure lets you quickly produce date-style range filters in the Django Admin interface without having to create a new class for each one.

It follows Python range semantics, with the lower value using a _gte test and the upper value using an _lt test.

Here's an example of how I'm using it in one of my projects:

list_filter = ('complete',
        ('chapters', makeRangeFieldListFilter([
            (_('1'), 1, 2),
            (_('2 to 10'), 2, 10),
            (_('11 to 30'), 11, 30),
            (_('31 to 100'), 31, 100),
            (_('At least 100'), 100, None),
        ], nullable=True)),
        ('word_count', makeRangeFieldListFilter([
            (_('Less than 1000'), None, 1000),
            (_('1K to 5K'), 1000, 5000),
            (_('5K to 10K'), 5000, 10000),
            (_('10K to 75K'), 10000, 75000),
            (_('75K to 150K'), 75000, 150000),
            (_('150K to 300K'), 150000, 300000),
            (_('At least 300K'), 300000, None),
        ], nullable=True)),
        ('derivatives_count', makeRangeFieldListFilter([
            (_('None'), 0, 1),
            (_('1 to 5'), 1, 5),
            (_('5 to 50'), 5, 50),
            (_('50 to 1000'), 50, 1000),
            (_('At least 1000'), 1000, None),
        ])),
        'pub_date', 'upd_date')

It is based on code from DateFieldListFilter and BooleanFieldListFilter from django.contrib.admin.filters.

 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
from django.utils.translation import ugettext_lazy as _
from django.contrib.admin import FieldListFilter

def makeRangeFieldListFilter(lookups, nullable=False):
    class RangeFieldListFilter(FieldListFilter):
        def __init__(self, field, request, params, model, model_admin, field_path):
            self.field_generic = '%s__' % field_path
            self.range_params = dict([(k, v) for k, v in params.items()
                                     if k.startswith(self.field_generic)])

            self.lookup_kwarg_start = '%s__gte' % field_path
            self.lookup_kwarg_stop = '%s__lt' % field_path
            self.lookup_kwarg_null = '%s__isnull' % field_path

            self.links = [ (_('Any value'), {}), ]
            for name, start, stop in lookups:
                query_params = {}
                if start is not None:
                    query_params[self.lookup_kwarg_start] = str(start)
                if stop is not None:
                    query_params[self.lookup_kwarg_stop] = str(stop)

                self.links.append((name, query_params))

            if nullable:
                self.links.append((_('Unknown'), {
                    self.lookup_kwarg_null: 'True'
                }))

            super(RangeFieldListFilter, self).__init__(
                field, request, params, model, model_admin, field_path)

        def expected_parameters(self):
            return [
                self.lookup_kwarg_start,
                self.lookup_kwarg_stop,
                self.lookup_kwarg_null
            ]

        def choices(self, cl):
            for title, param_dict in self.links:
                yield {
                    'selected': self.range_params == param_dict,
                    'query_string': cl.get_query_string(
                                        param_dict, [self.field_generic]),
                    'display': title,
                }

    return RangeFieldListFilter

More like this

  1. Group results by a range of values in admin sidebar by wgollino 7 years, 1 month ago
  2. SuperChoices by willhardy 6 years, 4 months ago
  3. Friendly ID by willhardy 6 years, 3 months ago
  4. Time ranges like 7-9 p.m. by sgb 7 years, 2 months ago
  5. Pattern to integer list function by marinho 7 years, 3 months ago

Comments

Please login first before commenting.