Login

Group results by a range of values in admin sidebar

Author:
wgollino
Posted:
February 6, 2008
Language:
Python
Version:
.96
Score:
7 (after 7 ratings)

Adds filtering by ranges of values in the admin filter sidebar. This allows rows in numerical fields to be grouped together (in this case, group by price):

By store price
All
< 100
100 - 200
200 - 500
500 - 2000
>= 200

To use:

  1. save the code as rangevaluesfilterspec.py in your app's directory
  2. add import rangevaluesfilterspec to your models.py
  3. add myfield.list_filter_range = [value1, value2, ...] to your filter field

Example:

from django.db import models
import rangevaluesfilterspec

class Product(models.Model):
    store_price = models.DecimalField(max_digits=10, decimal_places=2)
    store_price.list_filter_range = [100, 200, 500, 2000]

    class Admin:
        list_filter = ['store_price']

Note that two extra groups are added: less-than the lowest value, and greater-than-or-equal-to the highest value.

 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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# Author: wgollino ([email protected])
# File: rangevaluesfilterspec.py
# 
# Adds filtering by ranges of values in the admin filter sidebar. The example below results in this filter:
#
# By store price
#   All
#   < 100
#   100 - 200
#   200 - 500
#   500 - 2000
#   >= 200
# 
#
# Example:
# 
# from django.db import models
# import rangevaluesfilterspec
#  
# class Product(models.Model):
#     store_price = models.DecimalField(max_digits=10, decimal_places=2)
#     store_price.list_filter_range = [100, 200, 500, 2000]
#
#     class Admin:
#         list_filter = ['store_price']


from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
from django.contrib.admin.filterspecs import FilterSpec

class RangeValuesFilterSpec(FilterSpec):
    """
    Adds filtering by ranges of values in the admin filter sidebar.
    Set range split points in the model field attribute 'list_filter_range'.
    
    my_model_field.list_filter_range = [100, 200, 300]
    
    Will define the ranges:
      my_model_field < 100
      my_model_field >= 100 AND my_model_field < 200
      my_model_field >= 200 AND my_model_field < 300
      my_model_field >= 300    
    """

    def __init__(self, f, request, params, model):
        super(RangeValuesFilterSpec, self).__init__(f, request, params, model)
        self.field_generic = '%s__' % self.field.name
        self.parsed_params = dict([(k, v) for k, v in params.items() if k.startswith(self.field_generic)])

        self.links = [(_('All'), {})]
        
        last_value = None
        for max_value in sorted(f.list_filter_range):
            max_value = str(max_value)
            if last_value == None:
                label = '&lt; ' + max_value
                range = {'%s__lt' % f.name: max_value}
            else:
                label = last_value + ' - ' + max_value
                range = {'%s__gte' % self.field.name: last_value, '%s__lt' % f.name: max_value}
            self.links.append((_(mark_safe(label)), range))
            last_value = max_value
        self.links.append((_(mark_safe('&ge; ' + max_value)), {'%s__gte' % f.name: max_value}))

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

# register the filter before the default filter
FilterSpec.filter_specs.insert(-1, (lambda f: hasattr(f, 'list_filter_range'), RangeValuesFilterSpec))

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

piramida (on March 23, 2009):

hanks! with a little updating (FilterSpec now passes model_admin as 6th parameter) works just as advertised.

#

magicrebirth (on April 23, 2009):

just to make it clear... you need to change these lines:

` ......

def __init__(self, f, request, params, model, model_admin):

    super(RangeValuesFilterSpec, self).__init__(f, request, params, model, model_admin)

....... `

#

Please login first before commenting.