Ticket #8528: AllValuesFilterSpec_Null.diff

File AllValuesFilterSpec_Null.diff, 5.0 KB (added by oyvind, 5 years ago)

Patch from #14467 with tests

  • django/contrib/admin/filterspecs.py

     
    161161class AllValuesFilterSpec(FilterSpec):
    162162    def __init__(self, f, request, params, model, model_admin):
    163163        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)
     164        self.lookup_kwarg = f.name
     165        self.lookup_kwarg_isnull = '%s__isnull' % f.name
     166        self.lookup_val = request.GET.get(self.lookup_kwarg, None)
     167        self.lookup_val_isnull = request.GET.get(self.lookup_kwarg_isnull, None)
     168        self.lookup_choices = model_admin.queryset(request).distinct().order_by(f.name).values_list(f.name, flat=True)
    166169
    167170    def title(self):
    168171        return self.field.verbose_name
    169172
    170173    def choices(self, cl):
    171         yield {'selected': self.lookup_val is None,
    172                'query_string': cl.get_query_string({}, [self.field.name]),
     174        yield {'selected': self.lookup_val is None and self.lookup_val_isnull is None,
     175               'query_string': cl.get_query_string({}, [self.lookup_kwarg, self.lookup_kwarg_isnull]),
    173176               'display': _('All')}
     177        include_none = False
    174178        for val in self.lookup_choices:
    175             val = smart_unicode(val[self.field.name])
     179            if val is None:
     180                include_none = True
     181                continue
     182            val = smart_unicode(val)
    176183            yield {'selected': self.lookup_val == val,
    177                    'query_string': cl.get_query_string({self.field.name: val}),
     184                   'query_string': cl.get_query_string({self.lookup_kwarg: val}, [self.lookup_kwarg_isnull]),
    178185                   'display': val}
     186        if include_none:
     187            yield {'selected': self.lookup_val_isnull is not None,
     188                    'query_string': cl.get_query_string({self.lookup_kwarg_isnull: 'True'}, [self.lookup_kwarg]),
     189                    'display': _('None')}
     190
    179191FilterSpec.register(lambda f: True, AllValuesFilterSpec)
  • tests/regressiontests/admin_filterspecs/tests.py

     
     1from django.utils import unittest
     2from django.test.client import RequestFactory
     3
     4from django.contrib import admin
     5from django.contrib.admin.views.main import ChangeList
     6
     7from models import OptionalAge
     8
     9class AllValuesFilterSpecTest(unittest.TestCase):
     10   
     11    def setUp(self):
     12        OptionalAge.objects.create(name='Sam', age=35)
     13        OptionalAge.objects.create(name='Tilk', age=135)
     14        OptionalAge.objects.create(name='Oneill', age=None)
     15        self.request_factory = RequestFactory()
     16
     17    def testAllValuesFilterSpecTest(self):
     18        m = OptionalAgeAdmin(OptionalAge, admin.site)
     19       
     20        r = self.request_factory.get('/', {'age__isnull': 'True'})
     21        cl = ChangeList(r, OptionalAge, m.list_display, m.list_display_links,
     22            m.list_filter, m.date_hierarchy, m.search_fields,
     23            m.list_select_related, m.list_per_page, m.list_editable, m)
     24           
     25        # Make sure cl.get_query_set() does not raise IncorrectLookupParameters
     26        queryset = cl.get_query_set()
     27
     28        # Make sure the last choice is None and is selected
     29        filterspec = cl.get_filters(r)[0][0]
     30        choices = list(filterspec.choices(cl))
     31        self.assertEquals(choices[3]['selected'], True)
     32        self.assertEquals(choices[3]['query_string'], '?age__isnull=True')
     33       
     34        r = self.request_factory.get('/', {'age': '135'})
     35        cl = ChangeList(r, OptionalAge, m.list_display, m.list_display_links,
     36            m.list_filter, m.date_hierarchy, m.search_fields,
     37            m.list_select_related, m.list_per_page, m.list_editable, m)
     38           
     39        # Make sure the correct choice is selected   
     40        filterspec = cl.get_filters(r)[0][0]
     41        choices = list(filterspec.choices(cl))
     42        self.assertEquals(choices[2]['selected'], True)
     43        self.assertEquals(choices[2]['query_string'], '?age=135')
     44
     45class OptionalAgeAdmin(admin.ModelAdmin):
     46    list_filter = ('age',)
     47    order_by = '-id'
  • tests/regressiontests/admin_filterspecs/models.py

     
     1from django.db import models
     2
     3class OptionalAge(models.Model):
     4    name = models.CharField(max_length=25)
     5    age = models.PositiveIntegerField(null=True, blank=True)
Back to Top