Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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
@gdub gdub authored
View
24 django/core/paginator.py
@@ -42,10 +42,12 @@ def page(self, number):
def _get_count(self):
"Returns the total number of objects, across all pages."
if self._count is None:
- from django.db.models.query import QuerySet
- if isinstance(self.object_list, QuerySet):
+ try:
self._count = self.object_list.count()
- else:
+ except (AttributeError, TypeError):
+ # AttributeError if object_list has no count() method.
+ # TypeError if object_list.count() requires arguments
+ # (i.e. is of type list).
self._count = len(self.object_list)
return self._count
count = property(_get_count)
@@ -169,22 +171,8 @@ def last_on_page(self, page_number):
return self.count
return page_number * self.num_per_page
- def _get_count(self):
- # The old API allowed for self.object_list to be either a QuerySet or a
- # list. Here, we handle both.
- if self._count is None:
- try:
- self._count = self.object_list.count()
- except (AttributeError, TypeError):
- # AttributeError if object_list has no count() method.
- # TypeError if object_list.count() requires arguments
- # (i.e. is of type list).
- self._count = len(self.object_list)
- return self._count
- count = property(_get_count)
-
# The old API called it "hits" instead of "count".
- hits = count
+ hits = Paginator.count
# The old API called it "pages" instead of "num_pages".
pages = Paginator.num_pages
View
10 docs/pagination.txt
@@ -59,10 +59,12 @@ page::
...
InvalidPage
-Note that you can give ``Paginator`` a list/tuple or a Django ``QuerySet``. The
-only difference is in implementation; if you pass a ``QuerySet``, the
-``Paginator`` will call its ``count()`` method instead of using ``len()``,
-because the former is more efficient.
+Note that you can give ``Paginator`` a list/tuple, a Django ``QuerySet``, or
+any other object with a ``count()`` or ``__len__()`` method. When determining
+the number of objects contained in the passed object, ``Paginator`` will first
+try calling ``count()``, then fallback to using ``len()`` if the passed object
+has no ``count()`` method. This allows objects such as Django's ``QuerySet`` to
+use a more efficient ``count()`` method when available.
``Paginator`` objects
=====================
View
25 tests/modeltests/pagination/models.py
@@ -140,6 +140,31 @@ def __unicode__(self):
>>> p.end_index()
5
+# Paginator can be passed other objects with a count() method.
+>>> class CountContainer:
+... def count(self):
+... return 42
+>>> paginator = Paginator(CountContainer(), 10)
+>>> paginator.count
+42
+>>> paginator.num_pages
+5
+>>> paginator.page_range
+[1, 2, 3, 4, 5]
+
+# Paginator can be passed other objects that implement __len__.
+>>> class LenContainer:
+... def __len__(self):
+... return 42
+>>> paginator = Paginator(LenContainer(), 10)
+>>> paginator.count
+42
+>>> paginator.num_pages
+5
+>>> paginator.page_range
+[1, 2, 3, 4, 5]
+
+
################################
# Legacy API (ObjectPaginator) #
################################

0 comments on commit 9a5301c

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