magic-removal: Updated django.core.paginator to work with QuerySet objects instead of Managers/Models

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2212 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2006-02-01 03:35:59 +00:00
parent a06b44bdc4
commit b01b9e3a87
1 changed files with 17 additions and 29 deletions

View File

@ -6,24 +6,17 @@ class InvalidPage(Exception):
class ObjectPaginator:
"""
This class makes pagination easy. Feed it a manager (an object with
get_count() and get_list() methods) or a model which has a default manager,
and a dictionary of arguments to be passed to those methods, plus the
number of objects you want on each page. Then read the hits and pages
properties to see how many pages it involves. Call get_page with a page
number (starting at 0) to get back a list of objects for that page.
This class makes pagination easy. Feed it a QuerySet, plus the number of
objects you want on each page. Then read the hits and pages properties to
see how many pages it involves. Call get_page with a page number (starting
at 0) to get back a list of objects for that page.
Finally, check if a page number has a next/prev page using
has_next_page(page_number) and has_previous_page(page_number).
"""
def __init__(self, manager_or_model, args, num_per_page, count_method='count', list_method='all'):
if hasattr(manager_or_model, '_default_manager'):
manager = manager_or_model._default_manager
else:
manager = manager_or_model
self.manager, self.args = manager, args
def __init__(self, query_set, num_per_page):
self.query_set = query_set
self.num_per_page = num_per_page
self.count_method, self.list_method = count_method, list_method
self._hits, self._pages = None, None
self._has_next = {} # Caches page_number -> has_next_boolean
@ -34,14 +27,17 @@ class ObjectPaginator:
raise InvalidPage
if page_number < 0:
raise InvalidPage
args = copy(self.args)
args['offset'] = page_number * self.num_per_page
# Retrieve one extra record, and check for the existence of that extra
# record to determine whether there's a next page.
args['limit'] = self.num_per_page + 1
object_list = getattr(self.manager, self.list_method)(**args)
limit = self.num_per_page + 1
offset = page_number * self.num_per_page
object_list = list(self.query_set[offset:offset+limit])
if not object_list:
raise InvalidPage
self._has_next[page_number] = (len(object_list) > self.num_per_page)
return object_list[:self.num_per_page]
@ -49,11 +45,8 @@ class ObjectPaginator:
"Does page $page_number have a 'next' page?"
if not self._has_next.has_key(page_number):
if self._pages is None:
args = copy(self.args)
args['offset'] = (page_number + 1) * self.num_per_page
args['limit'] = 1
object_list = getattr(self.manager, self.list_method)(**args)
self._has_next[page_number] = (object_list != [])
offset = (page_number + 1) * self.num_per_page
self._has_next[page_number] = len(self.query_set[offset:offset+1]) > 0
else:
self._has_next[page_number] = page_number < (self.pages - 1)
return self._has_next[page_number]
@ -63,12 +56,7 @@ class ObjectPaginator:
def _get_hits(self):
if self._hits is None:
order_args = copy(self.args)
if order_args.has_key('order_by'):
del order_args['order_by']
if order_args.has_key('select_related'):
del order_args['select_related']
self._hits = getattr(self.manager, self.count_method)(**order_args)
self._hits = self.query_set.count()
return self._hits
def _get_pages(self):