Django

Code

root/django/branches/newforms-admin/django/contrib/admin/filterspecs.py

Revision 6776, 7.6 kB (checked in by jkocherhans, 9 months ago)

newforms-admin: Merged trunk revision [6671].

  • Property svn:eol-style set to native
Line 
1 """
2 FilterSpec encapsulates the logic for displaying filters in the Django admin.
3 Filters are specified in models with the "list_filter" option.
4
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 """
8
9 from django.db import models
10 from django.utils.encoding import smart_unicode, iri_to_uri
11 from django.utils.translation import ugettext as _
12 from django.utils.html import escape
13 from django.utils.safestring import mark_safe
14 import datetime
15
16 class FilterSpec(object):
17     filter_specs = []
18     def __init__(self, f, request, params, model, model_admin):
19         self.field = f
20         self.params = params
21
22     def register(cls, test, factory):
23         cls.filter_specs.append((test, factory))
24     register = classmethod(register)
25
26     def create(cls, f, request, params, model, model_admin):
27         for test, factory in cls.filter_specs:
28             if test(f):
29                 return factory(f, request, params, model, model_admin)
30     create = classmethod(create)
31
32     def has_output(self):
33         return True
34
35     def choices(self, cl):
36         raise NotImplementedError()
37
38     def title(self):
39         return self.field.verbose_name
40
41     def output(self, cl):
42         t = []
43         if self.has_output():
44             t.append(_(u'<h3>By %s:</h3>\n<ul>\n') % escape(self.title()))
45
46             for choice in self.choices(cl):
47                 t.append(u'<li%s><a href="%s">%s</a></li>\n' % \
48                     ((choice['selected'] and ' class="selected"' or ''),
49                      iri_to_uri(choice['query_string']),
50                      choice['display']))
51             t.append('</ul>\n\n')
52         return mark_safe("".join(t))
53
54 class RelatedFilterSpec(FilterSpec):
55     def __init__(self, f, request, params, model, model_admin):
56         super(RelatedFilterSpec, self).__init__(f, request, params, model, model_admin)
57         if isinstance(f, models.ManyToManyField):
58             self.lookup_title = f.rel.to._meta.verbose_name
59         else:
60             self.lookup_title = f.verbose_name
61         self.lookup_kwarg = '%s__%s__exact' % (f.name, f.rel.to._meta.pk.name)
62         self.lookup_val = request.GET.get(self.lookup_kwarg, None)
63         self.lookup_choices = f.rel.to._default_manager.all()
64
65     def has_output(self):
66         return len(self.lookup_choices) > 1
67
68     def title(self):
69         return self.lookup_title
70
71     def choices(self, cl):
72         yield {'selected': self.lookup_val is None,
73                'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
74                'display': _('All')}
75         for val in self.lookup_choices:
76             pk_val = getattr(val, self.field.rel.to._meta.pk.attname)
77             yield {'selected': self.lookup_val == smart_unicode(pk_val),
78                    'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}),
79                    'display': val}
80
81 FilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)
82
83 class ChoicesFilterSpec(FilterSpec):
84     def __init__(self, f, request, params, model, model_admin):
85         super(ChoicesFilterSpec, self).__init__(f, request, params, model, model_admin)
86         self.lookup_kwarg = '%s__exact' % f.name
87         self.lookup_val = request.GET.get(self.lookup_kwarg, None)
88
89     def choices(self, cl):
90         yield {'selected': self.lookup_val is None,
91                'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
92                'display': _('All')}
93         for k, v in self.field.choices:
94             yield {'selected': smart_unicode(k) == self.lookup_val,
95                     'query_string': cl.get_query_string({self.lookup_kwarg: k}),
96                     'display': v}
97
98 FilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec)
99
100 class DateFieldFilterSpec(FilterSpec):
101     def __init__(self, f, request, params, model, model_admin):
102         super(DateFieldFilterSpec, self).__init__(f, request, params, model, model_admin)
103
104         self.field_generic = '%s__' % self.field.name
105
106         self.date_params = dict([(k, v) for k, v in params.items() if k.startswith(self.field_generic)])
107
108         today = datetime.date.today()
109         one_week_ago = today - datetime.timedelta(days=7)
110         today_str = isinstance(self.field, models.DateTimeField) and today.strftime('%Y-%m-%d 23:59:59') or today.strftime('%Y-%m-%d')
111
112         self.links = (
113             (_('Any date'), {}),
114             (_('Today'), {'%s__year' % self.field.name: str(today.year),
115                        '%s__month' % self.field.name: str(today.month),
116                        '%s__day' % self.field.name: str(today.day)}),
117             (_('Past 7 days'), {'%s__gte' % self.field.name: one_week_ago.strftime('%Y-%m-%d'),
118                              '%s__lte' % f.name: today_str}),
119             (_('This month'), {'%s__year' % self.field.name: str(today.year),
120                              '%s__month' % f.name: str(today.month)}),
121             (_('This year'), {'%s__year' % self.field.name: str(today.year)})
122         )
123
124     def title(self):
125         return self.field.verbose_name
126
127     def choices(self, cl):
128         for title, param_dict in self.links:
129             yield {'selected': self.date_params == param_dict,
130                    'query_string': cl.get_query_string(param_dict, [self.field_generic]),
131                    'display': title}
132
133 FilterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec)
134
135 class BooleanFieldFilterSpec(FilterSpec):
136     def __init__(self, f, request, params, model, model_admin):
137         super(BooleanFieldFilterSpec, self).__init__(f, request, params, model, model_admin)
138         self.lookup_kwarg = '%s__exact' % f.name
139         self.lookup_kwarg2 = '%s__isnull' % f.name
140         self.lookup_val = request.GET.get(self.lookup_kwarg, None)
141         self.lookup_val2 = request.GET.get(self.lookup_kwarg2, None)
142
143     def title(self):
144         return self.field.verbose_name
145
146     def choices(self, cl):
147         for k, v in ((_('All'), None), (_('Yes'), '1'), (_('No'), '0')):
148             yield {'selected': self.lookup_val == v and not self.lookup_val2,
149                    'query_string': cl.get_query_string({self.lookup_kwarg: v}, [self.lookup_kwarg2]),
150                    'display': k}
151         if isinstance(self.field, models.NullBooleanField):
152             yield {'selected': self.lookup_val2 == 'True',
153                    'query_string': cl.get_query_string({self.lookup_kwarg2: 'True'}, [self.lookup_kwarg]),
154                    'display': _('Unknown')}
155
156 FilterSpec.register(lambda f: isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField), BooleanFieldFilterSpec)
157
158 # This should be registered last, because it's a last resort. For example,
159 # if a field is eligible to use the BooleanFieldFilterSpec, that'd be much
160 # more appropriate, and the AllValuesFilterSpec won't get used for it.
161 class AllValuesFilterSpec(FilterSpec):
162     def __init__(self, f, request, params, model, model_admin):
163         super(AllValuesFilterSpec, self).__init__(f, request, params, model, model_admin)
164         self.lookup_val = request.GET.get(f.name, None)
165         self.lookup_choices = model_admin.queryset(request).distinct().order_by(f.name).values(f.name)
166
167     def title(self):
168         return self.field.verbose_name
169
170     def choices(self, cl):
171         yield {'selected': self.lookup_val is None,
172                'query_string': cl.get_query_string({}, [self.field.name]),
173                'display': _('All')}
174         for val in self.lookup_choices:
175             val = smart_unicode(val[self.field.name])
176             yield {'selected': self.lookup_val == val,
177                    'query_string': cl.get_query_string({self.field.name: val}),
178                    'display': val}
179 FilterSpec.register(lambda f: True, AllValuesFilterSpec)
Note: See TracBrowser for help on using the browser.