Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #15606 -- Ensured that boolean fields always use the Boolean fi…

…lterspec. Thanks to Martin Tiršel for the report

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15817 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 350a56ad4949762ba02f68cf1ba8bac2968507c0 1 parent 6d991d1
Russell Keith-Magee authored March 15, 2011
63  django/contrib/admin/filterspecs.py
@@ -121,6 +121,38 @@ def choices(self, cl):
121 121
         hasattr(f, 'rel') and bool(f.rel) or
122 122
         isinstance(f, models.related.RelatedObject)), RelatedFilterSpec)
123 123
 
  124
+class BooleanFieldFilterSpec(FilterSpec):
  125
+    def __init__(self, f, request, params, model, model_admin,
  126
+                 field_path=None):
  127
+        super(BooleanFieldFilterSpec, self).__init__(f, request, params, model,
  128
+                                                     model_admin,
  129
+                                                     field_path=field_path)
  130
+        self.lookup_kwarg = '%s__exact' % self.field_path
  131
+        self.lookup_kwarg2 = '%s__isnull' % self.field_path
  132
+        self.lookup_val = request.GET.get(self.lookup_kwarg, None)
  133
+        self.lookup_val2 = request.GET.get(self.lookup_kwarg2, None)
  134
+
  135
+    def title(self):
  136
+        return self.field.verbose_name
  137
+
  138
+    def choices(self, cl):
  139
+        for k, v in ((_('All'), None), (_('Yes'), '1'), (_('No'), '0')):
  140
+            yield {'selected': self.lookup_val == v and not self.lookup_val2,
  141
+                   'query_string': cl.get_query_string(
  142
+                                   {self.lookup_kwarg: v},
  143
+                                   [self.lookup_kwarg2]),
  144
+                   'display': k}
  145
+        if isinstance(self.field, models.NullBooleanField):
  146
+            yield {'selected': self.lookup_val2 == 'True',
  147
+                   'query_string': cl.get_query_string(
  148
+                                   {self.lookup_kwarg2: 'True'},
  149
+                                   [self.lookup_kwarg]),
  150
+                   'display': _('Unknown')}
  151
+
  152
+FilterSpec.register(lambda f: isinstance(f, models.BooleanField)
  153
+                              or isinstance(f, models.NullBooleanField),
  154
+                                 BooleanFieldFilterSpec)
  155
+
124 156
 class ChoicesFilterSpec(FilterSpec):
125 157
     def __init__(self, f, request, params, model, model_admin,
126 158
                  field_path=None):
@@ -187,37 +219,6 @@ def choices(self, cl):
187 219
 FilterSpec.register(lambda f: isinstance(f, models.DateField),
188 220
                               DateFieldFilterSpec)
189 221
 
190  
-class BooleanFieldFilterSpec(FilterSpec):
191  
-    def __init__(self, f, request, params, model, model_admin,
192  
-                 field_path=None):
193  
-        super(BooleanFieldFilterSpec, self).__init__(f, request, params, model,
194  
-                                                     model_admin,
195  
-                                                     field_path=field_path)
196  
-        self.lookup_kwarg = '%s__exact' % self.field_path
197  
-        self.lookup_kwarg2 = '%s__isnull' % self.field_path
198  
-        self.lookup_val = request.GET.get(self.lookup_kwarg, None)
199  
-        self.lookup_val2 = request.GET.get(self.lookup_kwarg2, None)
200  
-
201  
-    def title(self):
202  
-        return self.field.verbose_name
203  
-
204  
-    def choices(self, cl):
205  
-        for k, v in ((_('All'), None), (_('Yes'), '1'), (_('No'), '0')):
206  
-            yield {'selected': self.lookup_val == v and not self.lookup_val2,
207  
-                   'query_string': cl.get_query_string(
208  
-                                   {self.lookup_kwarg: v},
209  
-                                   [self.lookup_kwarg2]),
210  
-                   'display': k}
211  
-        if isinstance(self.field, models.NullBooleanField):
212  
-            yield {'selected': self.lookup_val2 == 'True',
213  
-                   'query_string': cl.get_query_string(
214  
-                                   {self.lookup_kwarg2: 'True'},
215  
-                                   [self.lookup_kwarg]),
216  
-                   'display': _('Unknown')}
217  
-
218  
-FilterSpec.register(lambda f: isinstance(f, models.BooleanField)
219  
-                              or isinstance(f, models.NullBooleanField),
220  
-                                 BooleanFieldFilterSpec)
221 222
 
222 223
 # This should be registered last, because it's a last resort. For example,
223 224
 # if a field is eligible to use the BooleanFieldFilterSpec, that'd be much
12  tests/regressiontests/admin_filterspecs/models.py
@@ -9,3 +9,15 @@ class Book(models.Model):
9 9
 
10 10
     def __unicode__(self):
11 11
         return self.title
  12
+
  13
+class BoolTest(models.Model):
  14
+    NO = False
  15
+    YES = True
  16
+    YES_NO_CHOICES = (
  17
+        (NO, 'no'),
  18
+        (YES, 'yes')
  19
+    )
  20
+    completed = models.BooleanField(
  21
+        default=NO,
  22
+        choices=YES_NO_CHOICES
  23
+    )
38  tests/regressiontests/admin_filterspecs/tests.py
@@ -6,7 +6,7 @@
6 6
 from django.contrib.admin.views.main import ChangeList
7 7
 from django.utils.encoding import force_unicode
8 8
 
9  
-from models import Book
  9
+from models import Book, BoolTest
10 10
 
11 11
 def select_by(dictlist, key, value):
12 12
     return [x for x in dictlist if x[key] == value][0]
@@ -26,6 +26,10 @@ def setUp(self):
26 26
         gipsy_book.contributors = [self.bob, lisa]
27 27
         gipsy_book.save()
28 28
 
  29
+        # BoolTests
  30
+        self.trueTest = BoolTest.objects.create(completed=True)
  31
+        self.falseTest = BoolTest.objects.create(completed=False)
  32
+
29 33
         self.request_factory = RequestFactory()
30 34
 
31 35
 
@@ -167,9 +171,41 @@ def test_RelatedFilterSpec_reverse_relationships(self):
167 171
         self.assertEqual(choice['selected'], True)
168 172
         self.assertEqual(choice['query_string'], '?books_contributed__id__exact=%d' % self.django_book.pk)
169 173
 
  174
+    def test_BooleanFilterSpec(self):
  175
+        modeladmin = BoolTestAdmin(BoolTest, admin.site)
  176
+
  177
+        request = self.request_factory.get('/')
  178
+        changelist = ChangeList(request, BoolTest, modeladmin.list_display, modeladmin.list_display_links,
  179
+            modeladmin.list_filter, modeladmin.date_hierarchy, modeladmin.search_fields,
  180
+            modeladmin.list_select_related, modeladmin.list_per_page, modeladmin.list_editable, modeladmin)
  181
+
  182
+        # Make sure changelist.get_query_set() does not raise IncorrectLookupParameters
  183
+        queryset = changelist.get_query_set()
  184
+
  185
+        # Make sure the last choice is None and is selected
  186
+        filterspec = changelist.get_filters(request)[0][0]
  187
+        self.assertEqual(force_unicode(filterspec.title()), u'completed')
  188
+        choices = list(filterspec.choices(changelist))
  189
+        self.assertEqual(choices[-1]['selected'], False)
  190
+        self.assertEqual(choices[-1]['query_string'], '?completed__exact=0')
  191
+
  192
+        request = self.request_factory.get('/', {'completed__exact': 1})
  193
+        changelist = self.get_changelist(request, BoolTest, modeladmin)
  194
+
  195
+        # Make sure the correct choice is selected
  196
+        filterspec = changelist.get_filters(request)[0][0]
  197
+        self.assertEqual(force_unicode(filterspec.title()), u'completed')
  198
+        # order of choices depends on User model, which has no order
  199
+        choice = select_by(filterspec.choices(changelist), "display", "Yes")
  200
+        self.assertEqual(choice['selected'], True)
  201
+        self.assertEqual(choice['query_string'], '?completed__exact=1')
  202
+
170 203
 class CustomUserAdmin(UserAdmin):
171 204
     list_filter = ('books_authored', 'books_contributed')
172 205
 
173 206
 class BookAdmin(admin.ModelAdmin):
174 207
     list_filter = ('year', 'author', 'contributors')
175 208
     order_by = '-id'
  209
+
  210
+class BoolTestAdmin(admin.ModelAdmin):
  211
+    list_filter = ('completed',)

0 notes on commit 350a56a

Please sign in to comment.
Something went wrong with that request. Please try again.