Ticket #15960: 15960.simplelistfilter-queryset-based-lookups.diff

File 15960.simplelistfilter-queryset-based-lookups.diff, 12.8 KB (added by Julien Phalip, 14 years ago)
  • django/contrib/admin/filters.py

    diff --git a/django/contrib/admin/filters.py b/django/contrib/admin/filters.py
    index 36dcea1..22ce36f 100644
    a b class SimpleListFilter(ListFilter):  
    6363            raise ImproperlyConfigured(
    6464                "The list filter '%s' does not specify "
    6565                "a 'parameter_name'." % self.__class__.__name__)
    66         lookup_choices = self.lookups(request)
     66        lookup_choices = self.lookups(request, model_admin)
    6767        if lookup_choices is None:
    6868            lookup_choices = ()
    6969        self.lookup_choices = lookup_choices
    class SimpleListFilter(ListFilter):  
    7878        """
    7979        return self.params.get(self.parameter_name, None)
    8080
    81     def lookups(self, request):
     81    def lookups(self, request, model_admin):
    8282        """
    8383        Must be overriden to return a list of tuples (value, verbose value)
    8484        """
  • docs/ref/contrib/admin/index.txt

    diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
    index e8bc597..6b403ed 100644
    a b subclass::  
    568568                   # Parameter for the filter that will be used in the URL query.
    569569                   parameter_name = 'decade'
    570570
    571                    def lookups(self, request):
     571                   def lookups(self, request, model_admin):
    572572                       """
    573573                       Returns a list of tuples. The first element in each
    574574                       tuple is the coded value for the option that will
    subclass::  
    578578                       """
    579579                       return (
    580580                           ('80s', 'in the eighties'),
    581                            ('other', 'other'),
     581                           ('90s', 'in the nineties'),
    582582                       )
    583583
    584584                   def queryset(self, request, queryset):
    585585                       """
    586586                       Returns the filtered queryset based on the value
    587587                       provided in the query string and retrievable via
    588                        ``value()``.
     588                       `self.value()`.
    589589                       """
    590590                       # Compare the requested value (either '80s' or 'other')
    591591                       # to decide how to filter the queryset.
    592592                       if self.value() == '80s':
    593593                           return queryset.filter(birthday__year__gte=1980,
    594594                                                   birthday__year__lte=1989)
    595                        if self.value() == 'other':
    596                            return queryset.filter(Q(year__lte=1979) |
    597                                                    Q(year__gte=1990))
     595                       if self.value() == '90s':
     596                           return queryset.filter(birthday__year__gte=1990,
     597                                                  birthday__year__lte=1999)
    598598
    599599               class PersonAdmin(ModelAdmin):
    600600                   list_filter = (DecadeBornListFilter,)
    subclass::  
    602602          .. note::
    603603
    604604              As a convenience, the ``HttpRequest`` object is passed to the
    605               filter's methods, for example::
     605              ``lookups`` and ``queryset`` methods, for example::
    606606
    607607                  class AuthDecadeBornListFilter(DecadeBornListFilter):
    608608
    609                       def lookups(self, request):
     609                      def lookups(self, request, model_admin):
    610610                          if request.user.is_superuser:
    611                               return super(AuthDecadeBornListFilter, self).lookups(request)
     611                              return super(AuthDecadeBornListFilter, self) \
     612                                         .lookups(request, model_admin)
    612613
    613614                      def queryset(self, request, queryset):
    614615                          if request.user.is_superuser:
    615                               return super(AuthDecadeBornListFilter, self).queryset(request, queryset)
     616                              return super(AuthDecadeBornListFilter, self) \
     617                                         .queryset(request, queryset)
     618
     619              Also as a convenience, the ``ModelAdmin`` objects is passed to the
     620              ``lookups`` method, for example if you want to base the lookups on the
     621              available data::
     622             
     623                  class AnotherDecadeBornListFilter(DecadeBornListFilter):
     624                 
     625                      def lookups(self, request, model_admin):
     626                          """
     627                          Only show the lookups if there actually is anyone born in
     628                          the corresponding decades.
     629                          """
     630                          born_in_80s = model_admin.queryset(request) \
     631                                            .filter(birthday__year__gte=1980,
     632                                                    birthday__year__lte=1989)
     633                          born_in_90s = model_admin.queryset(request) \
     634                                            .filter(birthday__year__gte=1990,
     635                                                    birthday__year__lte=1999)
     636                          options = tuple()
     637                          if born_in_80s.count() > 0:
     638                              options += (('80s', "in the eighties"),)
     639                          if books_90s.count() > 0:
     640                              options += (('90s', "in the nineties"),)
     641                          return options
    616642
    617643        * a tuple, where the first element is a field name and the second
    618644          element is a class inheriting from
  • tests/regressiontests/admin_filters/tests.py

    diff --git a/tests/regressiontests/admin_filters/tests.py b/tests/regressiontests/admin_filters/tests.py
    index 6b32475..72776d7 100644
    a b def select_by(dictlist, key, value):  
    1919
    2020class DecadeListFilter(SimpleListFilter):
    2121
    22     def lookups(self, request):
     22    def lookups(self, request, model_admin):
    2323        return (
     24            ('the 80s', "the 1980's"),
    2425            ('the 90s', "the 1990's"),
    2526            ('the 00s', "the 2000's"),
    2627            ('other', "other decades"),
    class DecadeListFilter(SimpleListFilter):  
    2829
    2930    def queryset(self, request, queryset):
    3031        decade = self.value()
     32        if decade == 'the 80s':
     33            return queryset.filter(year__gte=1980, year__lte=1989)
    3134        if decade == 'the 90s':
    3235            return queryset.filter(year__gte=1990, year__lte=1999)
    3336        if decade == 'the 00s':
    class DecadeListFilterWithoutParameter(DecadeListFilter):  
    4548
    4649class DecadeListFilterWithNoneReturningLookups(DecadeListFilterWithTitleAndParameter):
    4750
    48     def lookups(self, request):
     51    def lookups(self, request, model_admin):
    4952        pass
    5053
     54class DecadeListFilterWithQuerysetBasedLookups(DecadeListFilterWithTitleAndParameter):
     55
     56    def lookups(self, request, model_admin):
     57        books_80s = model_admin.queryset(request).filter(year__gte=1980, year__lte=1989)
     58        books_90s = model_admin.queryset(request).filter(year__gte=1990, year__lte=1999)
     59        books_00s = model_admin.queryset(request).filter(year__gte=2000, year__lte=2009)
     60        options = tuple()
     61        if books_80s.count() > 0:
     62            options += (('the 80s', "the 1980's"),)
     63        if books_90s.count() > 0:
     64            options += (('the 90s', "the 1990's"),)
     65        if books_00s.count() > 0:
     66            options += (('the 00s', "the 2000's"),)
     67        return options
     68       
     69   
    5170class CustomUserAdmin(UserAdmin):
    5271    list_filter = ('books_authored', 'books_contributed')
    5372
    class DecadeFilterBookAdminWithoutParameter(ModelAdmin):  
    6887class DecadeFilterBookAdminWithNoneReturningLookups(ModelAdmin):
    6988    list_filter = (DecadeListFilterWithNoneReturningLookups,)
    7089
     90class DecadeFilterBookAdminWithQuerysetBasedLookups(ModelAdmin):
     91    list_filter = (DecadeListFilterWithQuerysetBasedLookups,)
     92   
    7193class ListFiltersTests(TestCase):
    7294
    7395    def setUp(self):
    class ListFiltersTests(TestCase):  
    385407        self.assertEqual(choices[0]['selected'], True)
    386408        self.assertEqual(choices[0]['query_string'], '?')
    387409
     410        # Look for books in the 1980s ----------------------------------------
     411
     412        request = self.request_factory.get('/', {'publication-decade': 'the 80s'})
     413        changelist = self.get_changelist(request, Book, modeladmin)
     414
     415        # Make sure the correct queryset is returned
     416        queryset = changelist.get_query_set(request)
     417        self.assertEqual(list(queryset), [])
     418
     419        # Make sure the correct choice is selected
     420        filterspec = changelist.get_filters(request)[0][1]
     421        self.assertEqual(force_unicode(filterspec.title), u'publication decade')
     422        choices = list(filterspec.choices(changelist))
     423        self.assertEqual(choices[1]['display'], u'the 1980\'s')
     424        self.assertEqual(choices[1]['selected'], True)
     425        self.assertEqual(choices[1]['query_string'], '?publication-decade=the+80s')
     426       
    388427        # Look for books in the 1990s ----------------------------------------
    389428
    390429        request = self.request_factory.get('/', {'publication-decade': 'the 90s'})
    class ListFiltersTests(TestCase):  
    398437        filterspec = changelist.get_filters(request)[0][1]
    399438        self.assertEqual(force_unicode(filterspec.title), u'publication decade')
    400439        choices = list(filterspec.choices(changelist))
    401         self.assertEqual(choices[1]['display'], u'the 1990\'s')
    402         self.assertEqual(choices[1]['selected'], True)
    403         self.assertEqual(choices[1]['query_string'], '?publication-decade=the+90s')
     440        self.assertEqual(choices[2]['display'], u'the 1990\'s')
     441        self.assertEqual(choices[2]['selected'], True)
     442        self.assertEqual(choices[2]['query_string'], '?publication-decade=the+90s')
    404443
    405444        # Look for books in the 2000s ----------------------------------------
    406445
    class ListFiltersTests(TestCase):  
    415454        filterspec = changelist.get_filters(request)[0][1]
    416455        self.assertEqual(force_unicode(filterspec.title), u'publication decade')
    417456        choices = list(filterspec.choices(changelist))
    418         self.assertEqual(choices[2]['display'], u'the 2000\'s')
    419         self.assertEqual(choices[2]['selected'], True)
    420         self.assertEqual(choices[2]['query_string'], '?publication-decade=the+00s')
     457        self.assertEqual(choices[3]['display'], u'the 2000\'s')
     458        self.assertEqual(choices[3]['selected'], True)
     459        self.assertEqual(choices[3]['query_string'], '?publication-decade=the+00s')
    421460
    422461        # Combine multiple filters -------------------------------------------
    423462
    class ListFiltersTests(TestCase):  
    432471        filterspec = changelist.get_filters(request)[0][1]
    433472        self.assertEqual(force_unicode(filterspec.title), u'publication decade')
    434473        choices = list(filterspec.choices(changelist))
    435         self.assertEqual(choices[2]['display'], u'the 2000\'s')
    436         self.assertEqual(choices[2]['selected'], True)
    437         self.assertEqual(choices[2]['query_string'], '?publication-decade=the+00s&author__id__exact=%s' % self.alfred.pk)
     474        self.assertEqual(choices[3]['display'], u'the 2000\'s')
     475        self.assertEqual(choices[3]['selected'], True)
     476        self.assertEqual(choices[3]['query_string'], '?publication-decade=the+00s&author__id__exact=%s' % self.alfred.pk)
    438477
    439478        filterspec = changelist.get_filters(request)[0][0]
    440479        self.assertEqual(force_unicode(filterspec.title), u'author')
    class ListFiltersTests(TestCase):  
    472511        changelist = self.get_changelist(request, Book, modeladmin)
    473512        filterspec = changelist.get_filters(request)[0]
    474513        self.assertEqual(len(filterspec), 0)
     514
     515    def test_simplelistfilter_with_queryset_based_lookups(self):
     516        modeladmin = DecadeFilterBookAdminWithQuerysetBasedLookups(Book, site)
     517        request = self.request_factory.get('/', {})
     518        changelist = self.get_changelist(request, Book, modeladmin)
     519       
     520        filterspec = changelist.get_filters(request)[0][0]
     521        self.assertEqual(force_unicode(filterspec.title), u'publication decade')
     522        choices = list(filterspec.choices(changelist))
     523        self.assertEqual(len(choices), 3)
     524       
     525        self.assertEqual(choices[0]['display'], u'All')
     526        self.assertEqual(choices[0]['selected'], True)
     527        self.assertEqual(choices[0]['query_string'], '?')
     528       
     529        self.assertEqual(choices[1]['display'], u'the 1990\'s')
     530        self.assertEqual(choices[1]['selected'], False)
     531        self.assertEqual(choices[1]['query_string'], '?publication-decade=the+90s')
     532       
     533        self.assertEqual(choices[2]['display'], u'the 2000\'s')
     534        self.assertEqual(choices[2]['selected'], False)
     535        self.assertEqual(choices[2]['query_string'], '?publication-decade=the+00s')
Back to Top