Author: jezdez
Date: 2011-05-04 15:52:04 -0700 (Wed, 04 May 2011)
New Revision: 16152

Modified:
   django/trunk/django/contrib/admin/filters.py
   django/trunk/docs/ref/contrib/admin/index.txt
   django/trunk/tests/regressiontests/admin_filters/tests.py
Log:
Fixed #15960 -- Extended list filer API added in r16144 slightly to pass the 
current model admin to the SimpleListFilter.lookups method to support finer 
grained control over what is filtered over. Many thanks to Carl Meyer and 
Julien Phalip for the suggestion and patch.

Modified: django/trunk/django/contrib/admin/filters.py
===================================================================
--- django/trunk/django/contrib/admin/filters.py        2011-05-04 17:36:34 UTC 
(rev 16151)
+++ django/trunk/django/contrib/admin/filters.py        2011-05-04 22:52:04 UTC 
(rev 16152)
@@ -63,10 +63,10 @@
             raise ImproperlyConfigured(
                 "The list filter '%s' does not specify "
                 "a 'parameter_name'." % self.__class__.__name__)
-        lookup_choices = self.lookups(request)
+        lookup_choices = self.lookups(request, model_admin)
         if lookup_choices is None:
             lookup_choices = ()
-        self.lookup_choices = lookup_choices
+        self.lookup_choices = list(lookup_choices)
 
     def has_output(self):
         return len(self.lookup_choices) > 0
@@ -78,7 +78,7 @@
         """
         return self.params.get(self.parameter_name, None)
 
-    def lookups(self, request):
+    def lookups(self, request, model_admin):
         """
         Must be overriden to return a list of tuples (value, verbose value)
         """

Modified: django/trunk/docs/ref/contrib/admin/index.txt
===================================================================
--- django/trunk/docs/ref/contrib/admin/index.txt       2011-05-04 17:36:34 UTC 
(rev 16151)
+++ django/trunk/docs/ref/contrib/admin/index.txt       2011-05-04 22:52:04 UTC 
(rev 16152)
@@ -555,9 +555,7 @@
           attributes to and override the ``lookups`` and ``queryset`` methods,
           e.g.::
 
-               from django.db.models import Q
                from django.utils.translation import ugettext_lazy as _
-
                from django.contrib.admin import SimpleListFilter
 
                class DecadeBornListFilter(SimpleListFilter):
@@ -568,7 +566,7 @@
                    # Parameter for the filter that will be used in the URL 
query.
                    parameter_name = 'decade'
 
-                   def lookups(self, request):
+                   def lookups(self, request, model_admin):
                        """
                        Returns a list of tuples. The first element in each
                        tuple is the coded value for the option that will
@@ -577,24 +575,24 @@
                        in the right sidebar.
                        """
                        return (
-                           ('80s', 'in the eighties'),
-                           ('other', 'other'),
+                           ('80s', _('in the eighties')),
+                           ('90s', _('in the nineties')),
                        )
 
                    def queryset(self, request, queryset):
                        """
                        Returns the filtered queryset based on the value
                        provided in the query string and retrievable via
-                       ``value()``.
+                       `self.value()`.
                        """
                        # Compare the requested value (either '80s' or 'other')
                        # to decide how to filter the queryset.
                        if self.value() == '80s':
                            return queryset.filter(birthday__year__gte=1980,
                                                    birthday__year__lte=1989)
-                       if self.value() == 'other':
-                           return queryset.filter(Q(year__lte=1979) |
-                                                   Q(year__gte=1990))
+                       if self.value() == '90s':
+                           return queryset.filter(birthday__year__gte=1990,
+                                                  birthday__year__lte=1999)
 
                class PersonAdmin(ModelAdmin):
                    list_filter = (DecadeBornListFilter,)
@@ -602,18 +600,39 @@
           .. note::
 
               As a convenience, the ``HttpRequest`` object is passed to the
-              filter's methods, for example::
+              ``lookups`` and ``queryset`` methods, for example::
 
                   class AuthDecadeBornListFilter(DecadeBornListFilter):
 
-                      def lookups(self, request):
+                      def lookups(self, request, model_admin):
                           if request.user.is_superuser:
-                              return super(AuthDecadeBornListFilter, 
self).lookups(request)
+                              return super(AuthDecadeBornListFilter,
+                                  self).lookups(request, model_admin)
 
                       def queryset(self, request, queryset):
                           if request.user.is_superuser:
-                              return super(AuthDecadeBornListFilter, 
self).queryset(request, queryset)
+                              return super(AuthDecadeBornListFilter,
+                                  self).queryset(request, queryset)
 
+              Also as a convenience, the ``ModelAdmin`` object is passed to
+              the ``lookups`` method, for example if you want to base the
+              lookups on the available data::
+
+                  class AdvancedDecadeBornListFilter(DecadeBornListFilter):
+
+                      def lookups(self, request, model_admin):
+                          """
+                          Only show the lookups if there actually is
+                          anyone born in the corresponding decades.
+                          """
+                          qs = model_admin.queryset(request)
+                          if qs.filter(birthday__year__gte=1980,
+                                        birthday__year__lte=1989).exists():
+                              yield ('80s', _('in the eighties'))
+                          if qs.filter(birthday__year__gte=1990,
+                                        birthday__year__lte=1999).exists():
+                              yield ('90s', _('in the nineties'))
+
         * a tuple, where the first element is a field name and the second
           element is a class inheriting from
           :mod:`django.contrib.admin.FieldListFilter`, for example::

Modified: django/trunk/tests/regressiontests/admin_filters/tests.py
===================================================================
--- django/trunk/tests/regressiontests/admin_filters/tests.py   2011-05-04 
17:36:34 UTC (rev 16151)
+++ django/trunk/tests/regressiontests/admin_filters/tests.py   2011-05-04 
22:52:04 UTC (rev 16152)
@@ -19,8 +19,9 @@
 
 class DecadeListFilter(SimpleListFilter):
 
-    def lookups(self, request):
+    def lookups(self, request, model_admin):
         return (
+            ('the 80s', "the 1980's"),
             ('the 90s', "the 1990's"),
             ('the 00s', "the 2000's"),
             ('other', "other decades"),
@@ -28,6 +29,8 @@
 
     def queryset(self, request, queryset):
         decade = self.value()
+        if decade == 'the 80s':
+            return queryset.filter(year__gte=1980, year__lte=1989)
         if decade == 'the 90s':
             return queryset.filter(year__gte=1990, year__lte=1999)
         if decade == 'the 00s':
@@ -45,9 +48,20 @@
 
 class 
DecadeListFilterWithNoneReturningLookups(DecadeListFilterWithTitleAndParameter):
 
-    def lookups(self, request):
+    def lookups(self, request, model_admin):
         pass
 
+class 
DecadeListFilterWithQuerysetBasedLookups(DecadeListFilterWithTitleAndParameter):
+
+    def lookups(self, request, model_admin):
+        qs = model_admin.queryset(request)
+        if qs.filter(year__gte=1980, year__lte=1989).exists():
+            yield ('the 80s', "the 1980's")
+        if qs.filter(year__gte=1990, year__lte=1999).exists():
+            yield ('the 90s', "the 1990's")
+        if qs.filter(year__gte=2000, year__lte=2009).exists():
+            yield ('the 00s', "the 2000's")
+
 class CustomUserAdmin(UserAdmin):
     list_filter = ('books_authored', 'books_contributed')
 
@@ -68,6 +82,9 @@
 class DecadeFilterBookAdminWithNoneReturningLookups(ModelAdmin):
     list_filter = (DecadeListFilterWithNoneReturningLookups,)
 
+class DecadeFilterBookAdminWithQuerysetBasedLookups(ModelAdmin):
+    list_filter = (DecadeListFilterWithQuerysetBasedLookups,)
+
 class ListFiltersTests(TestCase):
 
     def setUp(self):
@@ -385,6 +402,23 @@
         self.assertEqual(choices[0]['selected'], True)
         self.assertEqual(choices[0]['query_string'], '?')
 
+        # Look for books in the 1980s ----------------------------------------
+
+        request = self.request_factory.get('/', {'publication-decade': 'the 
80s'})
+        changelist = self.get_changelist(request, Book, modeladmin)
+
+        # Make sure the correct queryset is returned
+        queryset = changelist.get_query_set(request)
+        self.assertEqual(list(queryset), [])
+
+        # Make sure the correct choice is selected
+        filterspec = changelist.get_filters(request)[0][1]
+        self.assertEqual(force_unicode(filterspec.title), u'publication 
decade')
+        choices = list(filterspec.choices(changelist))
+        self.assertEqual(choices[1]['display'], u'the 1980\'s')
+        self.assertEqual(choices[1]['selected'], True)
+        self.assertEqual(choices[1]['query_string'], 
'?publication-decade=the+80s')
+
         # Look for books in the 1990s ----------------------------------------
 
         request = self.request_factory.get('/', {'publication-decade': 'the 
90s'})
@@ -398,9 +432,9 @@
         filterspec = changelist.get_filters(request)[0][1]
         self.assertEqual(force_unicode(filterspec.title), u'publication 
decade')
         choices = list(filterspec.choices(changelist))
-        self.assertEqual(choices[1]['display'], u'the 1990\'s')
-        self.assertEqual(choices[1]['selected'], True)
-        self.assertEqual(choices[1]['query_string'], 
'?publication-decade=the+90s')
+        self.assertEqual(choices[2]['display'], u'the 1990\'s')
+        self.assertEqual(choices[2]['selected'], True)
+        self.assertEqual(choices[2]['query_string'], 
'?publication-decade=the+90s')
 
         # Look for books in the 2000s ----------------------------------------
 
@@ -415,9 +449,9 @@
         filterspec = changelist.get_filters(request)[0][1]
         self.assertEqual(force_unicode(filterspec.title), u'publication 
decade')
         choices = list(filterspec.choices(changelist))
-        self.assertEqual(choices[2]['display'], u'the 2000\'s')
-        self.assertEqual(choices[2]['selected'], True)
-        self.assertEqual(choices[2]['query_string'], 
'?publication-decade=the+00s')
+        self.assertEqual(choices[3]['display'], u'the 2000\'s')
+        self.assertEqual(choices[3]['selected'], True)
+        self.assertEqual(choices[3]['query_string'], 
'?publication-decade=the+00s')
 
         # Combine multiple filters -------------------------------------------
 
@@ -432,9 +466,9 @@
         filterspec = changelist.get_filters(request)[0][1]
         self.assertEqual(force_unicode(filterspec.title), u'publication 
decade')
         choices = list(filterspec.choices(changelist))
-        self.assertEqual(choices[2]['display'], u'the 2000\'s')
-        self.assertEqual(choices[2]['selected'], True)
-        self.assertEqual(choices[2]['query_string'], 
'?publication-decade=the+00s&author__id__exact=%s' % self.alfred.pk)
+        self.assertEqual(choices[3]['display'], u'the 2000\'s')
+        self.assertEqual(choices[3]['selected'], True)
+        self.assertEqual(choices[3]['query_string'], 
'?publication-decade=the+00s&author__id__exact=%s' % self.alfred.pk)
 
         filterspec = changelist.get_filters(request)[0][0]
         self.assertEqual(force_unicode(filterspec.title), u'author')
@@ -472,3 +506,25 @@
         changelist = self.get_changelist(request, Book, modeladmin)
         filterspec = changelist.get_filters(request)[0]
         self.assertEqual(len(filterspec), 0)
+
+    def test_simplelistfilter_with_queryset_based_lookups(self):
+        modeladmin = DecadeFilterBookAdminWithQuerysetBasedLookups(Book, site)
+        request = self.request_factory.get('/', {})
+        changelist = self.get_changelist(request, Book, modeladmin)
+
+        filterspec = changelist.get_filters(request)[0][0]
+        self.assertEqual(force_unicode(filterspec.title), u'publication 
decade')
+        choices = list(filterspec.choices(changelist))
+        self.assertEqual(len(choices), 3)
+
+        self.assertEqual(choices[0]['display'], u'All')
+        self.assertEqual(choices[0]['selected'], True)
+        self.assertEqual(choices[0]['query_string'], '?')
+
+        self.assertEqual(choices[1]['display'], u'the 1990\'s')
+        self.assertEqual(choices[1]['selected'], False)
+        self.assertEqual(choices[1]['query_string'], 
'?publication-decade=the+90s')
+
+        self.assertEqual(choices[2]['display'], u'the 2000\'s')
+        self.assertEqual(choices[2]['selected'], False)
+        self.assertEqual(choices[2]['query_string'], 
'?publication-decade=the+00s')

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-updates@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to