1.9.30 sync.
[gae.git] / python / lib / django-0.96 / django / contrib / admin / filterspecs.py
blob8c2b82147e0e94e9d5ffe317569909930b8dda64
1 """
2 FilterSpec encapsulates the logic for displaying filters in the Django admin.
3 Filters are specified in models with the "list_filter" option.
5 Each filter subclass knows how to display a filter for a field that passes a
6 certain test -- e.g. being a DateField or ForeignKey.
7 """
9 from django.db import models
10 import datetime
12 class FilterSpec(object):
13 filter_specs = []
14 def __init__(self, f, request, params, model):
15 self.field = f
16 self.params = params
18 def register(cls, test, factory):
19 cls.filter_specs.append((test, factory))
20 register = classmethod(register)
22 def create(cls, f, request, params, model):
23 for test, factory in cls.filter_specs:
24 if test(f):
25 return factory(f, request, params, model)
26 create = classmethod(create)
28 def has_output(self):
29 return True
31 def choices(self, cl):
32 raise NotImplementedError()
34 def title(self):
35 return self.field.verbose_name
37 def output(self, cl):
38 t = []
39 if self.has_output():
40 t.append(_('<h3>By %s:</h3>\n<ul>\n') % self.title())
42 for choice in self.choices(cl):
43 t.append('<li%s><a href="%s">%s</a></li>\n' % \
44 ((choice['selected'] and ' class="selected"' or ''),
45 choice['query_string'] ,
46 choice['display']))
47 t.append('</ul>\n\n')
48 return "".join(t)
50 class RelatedFilterSpec(FilterSpec):
51 def __init__(self, f, request, params, model):
52 super(RelatedFilterSpec, self).__init__(f, request, params, model)
53 if isinstance(f, models.ManyToManyField):
54 self.lookup_title = f.rel.to._meta.verbose_name
55 else:
56 self.lookup_title = f.verbose_name
57 self.lookup_kwarg = '%s__%s__exact' % (f.name, f.rel.to._meta.pk.name)
58 self.lookup_val = request.GET.get(self.lookup_kwarg, None)
59 self.lookup_choices = f.rel.to._default_manager.all()
61 def has_output(self):
62 return len(self.lookup_choices) > 1
64 def title(self):
65 return self.lookup_title
67 def choices(self, cl):
68 yield {'selected': self.lookup_val is None,
69 'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
70 'display': _('All')}
71 for val in self.lookup_choices:
72 pk_val = getattr(val, self.field.rel.to._meta.pk.attname)
73 yield {'selected': self.lookup_val == str(pk_val),
74 'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}),
75 'display': val}
77 FilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)
79 class ChoicesFilterSpec(FilterSpec):
80 def __init__(self, f, request, params, model):
81 super(ChoicesFilterSpec, self).__init__(f, request, params, model)
82 self.lookup_kwarg = '%s__exact' % f.name
83 self.lookup_val = request.GET.get(self.lookup_kwarg, None)
85 def choices(self, cl):
86 yield {'selected': self.lookup_val is None,
87 'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
88 'display': _('All')}
89 for k, v in self.field.choices:
90 yield {'selected': str(k) == self.lookup_val,
91 'query_string': cl.get_query_string({self.lookup_kwarg: k}),
92 'display': v}
94 FilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec)
96 class DateFieldFilterSpec(FilterSpec):
97 def __init__(self, f, request, params, model):
98 super(DateFieldFilterSpec, self).__init__(f, request, params, model)
100 self.field_generic = '%s__' % self.field.name
102 self.date_params = dict([(k, v) for k, v in params.items() if k.startswith(self.field_generic)])
104 today = datetime.date.today()
105 one_week_ago = today - datetime.timedelta(days=7)
106 today_str = isinstance(self.field, models.DateTimeField) and today.strftime('%Y-%m-%d 23:59:59') or today.strftime('%Y-%m-%d')
108 self.links = (
109 (_('Any date'), {}),
110 (_('Today'), {'%s__year' % self.field.name: str(today.year),
111 '%s__month' % self.field.name: str(today.month),
112 '%s__day' % self.field.name: str(today.day)}),
113 (_('Past 7 days'), {'%s__gte' % self.field.name: one_week_ago.strftime('%Y-%m-%d'),
114 '%s__lte' % f.name: today_str}),
115 (_('This month'), {'%s__year' % self.field.name: str(today.year),
116 '%s__month' % f.name: str(today.month)}),
117 (_('This year'), {'%s__year' % self.field.name: str(today.year)})
120 def title(self):
121 return self.field.verbose_name
123 def choices(self, cl):
124 for title, param_dict in self.links:
125 yield {'selected': self.date_params == param_dict,
126 'query_string': cl.get_query_string(param_dict, [self.field_generic]),
127 'display': title}
129 FilterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec)
131 class BooleanFieldFilterSpec(FilterSpec):
132 def __init__(self, f, request, params, model):
133 super(BooleanFieldFilterSpec, self).__init__(f, request, params, model)
134 self.lookup_kwarg = '%s__exact' % f.name
135 self.lookup_kwarg2 = '%s__isnull' % f.name
136 self.lookup_val = request.GET.get(self.lookup_kwarg, None)
137 self.lookup_val2 = request.GET.get(self.lookup_kwarg2, None)
139 def title(self):
140 return self.field.verbose_name
142 def choices(self, cl):
143 for k, v in ((_('All'), None), (_('Yes'), '1'), (_('No'), '0')):
144 yield {'selected': self.lookup_val == v and not self.lookup_val2,
145 'query_string': cl.get_query_string({self.lookup_kwarg: v}, [self.lookup_kwarg2]),
146 'display': k}
147 if isinstance(self.field, models.NullBooleanField):
148 yield {'selected': self.lookup_val2 == 'True',
149 'query_string': cl.get_query_string({self.lookup_kwarg2: 'True'}, [self.lookup_kwarg]),
150 'display': _('Unknown')}
152 FilterSpec.register(lambda f: isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField), BooleanFieldFilterSpec)
154 # This should be registered last, because it's a last resort. For example,
155 # if a field is eligible to use the BooleanFieldFilterSpec, that'd be much
156 # more appropriate, and the AllValuesFilterSpec won't get used for it.
157 class AllValuesFilterSpec(FilterSpec):
158 def __init__(self, f, request, params, model):
159 super(AllValuesFilterSpec, self).__init__(f, request, params, model)
160 self.lookup_val = request.GET.get(f.name, None)
161 self.lookup_choices = model._meta.admin.manager.distinct().order_by(f.name).values(f.name)
163 def title(self):
164 return self.field.verbose_name
166 def choices(self, cl):
167 yield {'selected': self.lookup_val is None,
168 'query_string': cl.get_query_string({}, [self.field.name]),
169 'display': _('All')}
170 for val in self.lookup_choices:
171 val = str(val[self.field.name])
172 yield {'selected': self.lookup_val == val,
173 'query_string': cl.get_query_string({self.field.name: val}),
174 'display': val}
175 FilterSpec.register(lambda f: True, AllValuesFilterSpec)