class
Paginator:
def
__init__(
self
, object_list, per_page, orphans
=
0
,
allow_empty_first_page
=
True
):
self
.object_list
=
object_list
self
._check_object_list_is_ordered()
self
.per_page
=
int
(per_page)
self
.orphans
=
int
(orphans)
self
.allow_empty_first_page
=
allow_empty_first_page
def
validate_number(
self
, number):
try
:
if
isinstance
(number,
float
)
and
not
number.is_integer():
raise
ValueError
number
=
int
(number)
except
(TypeError, ValueError):
raise
PageNotAnInteger(_(
'That page number is not an integer'
))
if
number <
1
:
raise
EmptyPage(_(
'That page number is less than 1'
))
if
number >
self
.num_pages:
if
number
=
=
1
and
self
.allow_empty_first_page:
pass
else
:
raise
EmptyPage(_(
'That page contains no results'
))
return
number
def
get_page(
self
, number):
try
:
number
=
self
.validate_number(number)
except
PageNotAnInteger:
number
=
1
except
EmptyPage:
number
=
self
.num_pages
return
self
.page(number)
def
page(
self
, number):
number
=
self
.validate_number(number)
bottom
=
(number
-
1
)
*
self
.per_page
top
=
bottom
+
self
.per_page
if
top
+
self
.orphans >
=
self
.count:
top
=
self
.count
return
self
._get_page(
self
.object_list[bottom:top], number,
self
)
def
_get_page(
self
,
*
args,
*
*
kwargs):
return
Page(
*
args,
*
*
kwargs)
@cached_property
def
count(
self
):
c
=
getattr
(
self
.object_list,
'count'
,
None
)
if
callable
(c)
and
not
inspect.isbuiltin(c)
and
method_has_no_args(c):
return
c()
return
len
(
self
.object_list)
@cached_property
def
num_pages(
self
):
if
self
.count
=
=
0
and
not
self
.allow_empty_first_page:
return
0
hits
=
max
(
1
,
self
.count
-
self
.orphans)
return
ceil(hits
/
self
.per_page)
@property
def
page_range(
self
):
return
range
(
1
,
self
.num_pages
+
1
)
def
_check_object_list_is_ordered(
self
):
ordered
=
getattr
(
self
.object_list,
'ordered'
,
None
)
if
ordered
is
not
None
and
not
ordered:
obj_list_repr
=
(
'{} {}'
.
format
(
self
.object_list.model,
self
.object_list.__class__.__name__)
if
hasattr
(
self
.object_list,
'model'
)
else
'{!r}'
.
format
(
self
.object_list)
)
warnings.warn(
'Pagination may yield inconsistent results with an unordered '
'object_list: {}.'
.
format
(obj_list_repr),
UnorderedObjectListWarning,
stacklevel
=
3
)