Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Made the Paginator class a bit more backwards compatible with the lec…

…acy `ObjectPaginator` class by using the `ObjectPaginator`'s `_get_count` method. Instead of explicitly checking for an instance of `QuerySet`, this now allows any object with a `count()` or `__len__()` method defined to be passed to Paginator. For one, this is useful when you have custom `QuerySet`-like classes that implement a `count()` method but don't inherit from `QuerySet` explicitly.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@8121 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 9a5301ccbc08d5e4f78ae6a8a39330196cdd5f66 1 parent 6a287ed
Gary Wilson Jr. authored
24  django/core/paginator.py
@@ -42,10 +42,12 @@ def page(self, number):
42 42
     def _get_count(self):
43 43
         "Returns the total number of objects, across all pages."
44 44
         if self._count is None:
45  
-            from django.db.models.query import QuerySet
46  
-            if isinstance(self.object_list, QuerySet):
  45
+            try:
47 46
                 self._count = self.object_list.count()
48  
-            else:
  47
+            except (AttributeError, TypeError):
  48
+                # AttributeError if object_list has no count() method.
  49
+                # TypeError if object_list.count() requires arguments
  50
+                # (i.e. is of type list).
49 51
                 self._count = len(self.object_list)
50 52
         return self._count
51 53
     count = property(_get_count)
@@ -169,22 +171,8 @@ def last_on_page(self, page_number):
169 171
             return self.count
170 172
         return page_number * self.num_per_page
171 173
 
172  
-    def _get_count(self):
173  
-        # The old API allowed for self.object_list to be either a QuerySet or a
174  
-        # list. Here, we handle both.
175  
-        if self._count is None:
176  
-            try:
177  
-                self._count = self.object_list.count()
178  
-            except (AttributeError, TypeError):
179  
-                # AttributeError if object_list has no count() method.
180  
-                # TypeError if object_list.count() requires arguments
181  
-                # (i.e. is of type list).
182  
-                self._count = len(self.object_list)
183  
-        return self._count
184  
-    count = property(_get_count)
185  
-
186 174
     # The old API called it "hits" instead of "count".
187  
-    hits = count
  175
+    hits = Paginator.count
188 176
 
189 177
     # The old API called it "pages" instead of "num_pages".
190 178
     pages = Paginator.num_pages
10  docs/pagination.txt
@@ -59,10 +59,12 @@ page::
59 59
     ...
60 60
     InvalidPage
61 61
 
62  
-Note that you can give ``Paginator`` a list/tuple or a Django ``QuerySet``. The
63  
-only difference is in implementation; if you pass a ``QuerySet``, the
64  
-``Paginator`` will call its ``count()`` method instead of using ``len()``,
65  
-because the former is more efficient.
  62
+Note that you can give ``Paginator`` a list/tuple, a Django ``QuerySet``, or
  63
+any other object with a ``count()`` or ``__len__()`` method. When determining
  64
+the number of objects contained in the passed object, ``Paginator`` will first
  65
+try calling ``count()``, then fallback to using ``len()`` if the passed object
  66
+has no ``count()`` method. This allows objects such as Django's ``QuerySet`` to
  67
+use a more efficient ``count()`` method when available.
66 68
 
67 69
 ``Paginator`` objects
68 70
 =====================
25  tests/modeltests/pagination/models.py
@@ -140,6 +140,31 @@ def __unicode__(self):
140 140
 >>> p.end_index()
141 141
 5
142 142
 
  143
+# Paginator can be passed other objects with a count() method.
  144
+>>> class CountContainer:
  145
+...     def count(self):
  146
+...         return 42
  147
+>>> paginator = Paginator(CountContainer(), 10)
  148
+>>> paginator.count
  149
+42
  150
+>>> paginator.num_pages
  151
+5
  152
+>>> paginator.page_range
  153
+[1, 2, 3, 4, 5]
  154
+
  155
+# Paginator can be passed other objects that implement __len__.
  156
+>>> class LenContainer:
  157
+...     def __len__(self):
  158
+...         return 42
  159
+>>> paginator = Paginator(LenContainer(), 10)
  160
+>>> paginator.count
  161
+42
  162
+>>> paginator.num_pages
  163
+5
  164
+>>> paginator.page_range
  165
+[1, 2, 3, 4, 5]
  166
+
  167
+
143 168
 ################################
144 169
 # Legacy API (ObjectPaginator) #
145 170
 ################################

0 notes on commit 9a5301c

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