- pip install 'coverage<4' # coverage>=4 has issues with python3
- pip install -q Django==$DJANGO_VERSION coveralls
- python setup.py egg_info
-script: coverage run --source='linaro_django_pagination' --omit *runner*,*test_project* setup.py test
+script: coverage run --source='fnp_django_pagination' --omit *runner*,*test_project* setup.py test
after_success:
- coveralls
matrix:
include COPYING
include doc/conf.py
recursive-include doc *.rst
-recursive-include linaro_django_pagination/locale *.po
-recursive-include linaro_django_pagination/templates/pagination *.html
-recursive-include linaro_django_pagination/test_project/example/templates *.html
+recursive-include fnp_django_pagination/locale *.po
+recursive-include fnp_django_pagination/templates/pagination *.html
+recursive-include fnp_django_pagination/test_project/example/templates *.html
#
# The short X.Y version.
import versiontools
-import linaro_django_pagination
-version = "%d.%d" % linaro_django_pagination.__version__[0:2]
+import fnp_django_pagination
+version = "%d.%d" % fnp_django_pagination.__version__[0:2]
# The full version, including alpha/beta/rc tags.
-release = versiontools.format_version(linaro_django_pagination.__version__)
+release = versiontools.format_version(fnp_django_pagination.__version__)
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
--- /dev/null
+# Copyright (c) 2008, Eric Florenzano
+# Copyright (c) 2010, 2011 Linaro Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the author nor the names of other
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+fnp-django-pagination is a set of utilities for creating robust pagination
+tools throughout a django application.
+"""
+
+
+__version__ = (2, 2, 0, "final", 0)
--- /dev/null
+# Deutch translation of linaro-django-pagination
+# Copyright (c) 2009, linaro-django-pagination team
+# This file is distributed under the same license as the linaro-django-pagination package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: linaro-django-pagination master\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-03-16 16:26+0100\n"
+"PO-Revision-Date: 2012-01-26 13:27+0100\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "Zurück"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "Weiter"
--- /dev/null
+# Spanish translation of django-pagination
+# Copyright (c) 2010, Miguel Araujo
+# This file is distributed under the same license as the django-pagination package.
+# Miguel Araujo <miguel.araujo.perez@gmail.com>, 2010
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: linaro-django-pagination master\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-09-16 16:32+0200\n"
+"PO-Revision-Date: 2012-01-26 13:24+0100\n"
+"Last-Translator: Miguel Araujo <miguel.araujo.perez@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "anterior"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "siguiente"
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-07-11 12:51+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: templates/pagination/pagination.html:6
+#: templates/pagination/pagination.html:9
+msgid "previous"
+msgstr "edellinen"
+
+#: templates/pagination/pagination.html:30
+#: templates/pagination/pagination.html:33
+msgid "next"
+msgstr "seuraava"
--- /dev/null
+# French translation of linaro-django-pagination
+# Copyright (c) 2008, Julien Demoor
+# This file is distributed under the same license as the linaro-django-pagination package.
+# Julien Demoor <julien@jdemoor.com>, 2008
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: linaro-django-pagination master\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-10-24 00:41-0700\n"
+"PO-Revision-Date: 2012-01-26 13:25+0100\n"
+"Last-Translator: Julien Demoor <julien@jdemoor.com>\n"
+"Language-Team: French\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "précédente"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "suivante"
--- /dev/null
+# django-pagination Italian translation
+# Copyright (c) 2010 Fabio Corneti <info@corneti.com>
+# This file is distributed under the same license as the django-pagination package.
+# Fabio Corneti <info@corneti.com>, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: linaro-django-pagination-master\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-04-22 12:04+0200\n"
+"PO-Revision-Date: 2012-01-26 11:26+0100\n"
+"Last-Translator: Fabio Corneti <info@corneti.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: templates/pagination/default.html:6 templates/pagination/default.html:9
+msgid "previous"
+msgstr "precedenti"
+
+#: templates/pagination/default.html:30 templates/pagination/default.html:33
+msgid "next"
+msgstr "successive"
--- /dev/null
+# Norwegian translation of linaro-django-pagination.
+# Copyright (c) 2008, linaro-django-pagination team
+# This file is distributed under the same license as the linaro-django-pagination package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: linaro-django-pagination master\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-03-28 10:48+0200\n"
+"PO-Revision-Date: 2012-01-26 11:32+0100\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "Førre"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "Neste"
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (c) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-03-28 10:48+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "Forrige"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "Neste"
--- /dev/null
+# Polish translation of linaro-django-pagination.
+# Copyright (c) 2008, linaro-django-pagination team
+# This file is distributed under the same license as the linaro-django-pagination package.
+# Jarek Zgoda <jarek.zgoda@gmail.com>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: 1.0\n"
+"Report-Msgid-Bugs-To: linaro-django-pagination master\n"
+"POT-Creation-Date: 2008-10-24 00:41-0700\n"
+"PO-Revision-Date: 2012-01-26 11:29+0100\n"
+"Last-Translator: Jarek Zgoda <jarek.zgoda@gmail.com>\n"
+"Language-Team: PL <pl@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "poprzednia"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "następna"
--- /dev/null
+# linaro-django-pagination Portuguese translation.
+# Copyright (c) 2008, Alcides Fonseca
+# http://alcidesfonseca.com
+# This file is distributed under the WTFPL
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: linaro-django-pagination master\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-10-24 00:41-0700\n"
+"PO-Revision-Date: 2012-01-26 11:26+0100\n"
+"Last-Translator: Alcides Fonseca <me@alcidesfonseca.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "anterior"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "próximo"
--- /dev/null
+# Portuguese (Brazil) translation of django-pagination
+# Copyright (c) 2011, Tiago Samaha Cordeiro
+# This file is distributed under the same license as the django-pagination package.
+# Tiago Samaha Cordeiro <tiagosamaha@gmail.com>, 2011.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: linaro-django-pagination master\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-01-16 22:06-0200\n"
+"PO-Revision-Date: 2012-01-26 13:28+0100\n"
+"Last-Translator: Tiago Samaha Cordeiro <tiagosamaha@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: Portuguese Brazil\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "anterior"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "próximo"
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (c) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-07-11 16:14+0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "Предыдущая"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "Следующая"
--- /dev/null
+# Turkish translation of linaro-django-pagination.
+# Copyright (c) 2008, linaro-django-pagination team
+# This file is distributed under the same license as the linaro-django-pagination package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: linaro-django-pagination master\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-03-16 16:26+0100\n"
+"PO-Revision-Date: 2012-01-26 11:29+0100\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: templates/pagination/pagination.html:5
+#: templates/pagination/pagination.html:7
+msgid "previous"
+msgstr "Önceki"
+
+#: templates/pagination/pagination.html:21
+#: templates/pagination/pagination.html:23
+msgid "next"
+msgstr "Sonraki"
--- /dev/null
+# Copyright (c) 2008, Eric Florenzano
+# Copyright (c) 2010, 2011 Linaro Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the author nor the names of other
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+def get_page(self, suffix):
+ """
+ A function which will be monkeypatched onto the request to get the current
+ integer representing the current page.
+ """
+ try:
+ # REQUEST is deprecated as of Django 1.7.
+ key = 'page%s' % suffix
+ value = self.POST.get(key)
+ if value is None:
+ value = self.GET.get(key)
+ return int(value)
+ except (KeyError, ValueError, TypeError):
+ return 1
+
+
+class PaginationMiddleware(object):
+ """
+ Inserts a variable representing the current page onto the request object if
+ it exists in either **GET** or **POST** portions of the request.
+ """
+ def process_request(self, request):
+ request.__class__.page = get_page
--- /dev/null
+# Copyright (c) 2008, Eric Florenzano
+# Copyright (c) 2010, 2011 Linaro Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the author nor the names of other
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+from django.core.paginator import Paginator, Page, PageNotAnInteger, EmptyPage
+
+
+class InfinitePaginator(Paginator):
+ """
+ Paginator designed for cases when it's not important to know how many total
+ pages. This is useful for any object_list that has no count() method or
+ can be used to improve performance for MySQL by removing counts.
+
+ The orphans parameter has been removed for simplicity and there's a link
+ template string for creating the links to the next and previous pages.
+ """
+
+ def __init__(self, object_list, per_page, allow_empty_first_page=True,
+ link_template='/page/%d/'):
+ orphans = 0 # no orphans
+ super(InfinitePaginator, self).__init__(object_list, per_page, orphans,
+ allow_empty_first_page)
+ # no count or num pages
+ del self._num_pages, self._count
+ # bonus links
+ self.link_template = link_template
+
+ def validate_number(self, number):
+ """
+ Validates the given 1-based page number.
+ """
+ try:
+ number = int(number)
+ except ValueError:
+ raise PageNotAnInteger('That page number is not an integer')
+ if number < 1:
+ raise EmptyPage('That page number is less than 1')
+ return number
+
+ def page(self, number):
+ """
+ Returns a Page object for the given 1-based page number.
+ """
+ number = self.validate_number(number)
+ bottom = (number - 1) * self.per_page
+ top = bottom + self.per_page
+ page_items = self.object_list[bottom:top]
+ # check moved from validate_number
+ if not page_items:
+ if number == 1 and self.allow_empty_first_page:
+ pass
+ else:
+ raise EmptyPage('That page contains no results')
+ return InfinitePage(page_items, number, self)
+
+ def _get_count(self):
+ """
+ Returns the total number of objects, across all pages.
+ """
+ raise NotImplementedError
+ count = property(_get_count)
+
+ def _get_num_pages(self):
+ """
+ Returns the total number of pages.
+ """
+ raise NotImplementedError
+ num_pages = property(_get_num_pages)
+
+ def _get_page_range(self):
+ """
+ Returns a 1-based range of pages for iterating through within
+ a template for loop.
+ """
+ raise NotImplementedError
+ page_range = property(_get_page_range)
+
+
+class InfinitePage(Page):
+
+ def __repr__(self):
+ return '<Page %s>' % self.number
+
+ def has_next(self):
+ """
+ Checks for one more item than last on this page.
+ """
+ try:
+ self.paginator.object_list[self.number * self.paginator.per_page]
+ except IndexError:
+ return False
+ return True
+
+ def end_index(self):
+ """
+ Returns the 1-based index of the last object on this page,
+ relative to total objects found (hits).
+ """
+ return ((self.number - 1) * self.paginator.per_page +
+ len(self.object_list))
+
+ #Bonus methods for creating links
+
+ def next_link(self):
+ if self.has_next():
+ return self.paginator.link_template % (self.number + 1)
+ return None
+
+ def previous_link(self):
+ if self.has_previous():
+ return self.paginator.link_template % (self.number - 1)
+ return None
+
+
+class FinitePaginator(InfinitePaginator):
+ """
+ Paginator for cases when the list of items is already finite.
+
+ A good example is a list generated from an API call. This is a subclass
+ of InfinitePaginator because we have no idea how many items exist in the
+ full collection.
+
+ To accurately determine if the next page exists, a FinitePaginator MUST be
+ created with an object_list_plus that may contain more items than the
+ per_page count. Typically, you'll have an object_list_plus with one extra
+ item (if there's a next page). You'll also need to supply the offset from
+ the full collection in order to get the page start_index.
+
+ This is a very silly class but useful if you love the Django pagination
+ conventions.
+ """
+
+ def __init__(self, object_list_plus, per_page, offset=None,
+ allow_empty_first_page=True, link_template='/page/%d/'):
+ super(FinitePaginator, self).__init__(object_list_plus, per_page,
+ allow_empty_first_page, link_template)
+ self.offset = offset
+
+ def validate_number(self, number):
+ super(FinitePaginator, self).validate_number(number)
+ # check for an empty list to see if the page exists
+ if not self.object_list:
+ if number == 1 and self.allow_empty_first_page:
+ pass
+ else:
+ raise EmptyPage('That page contains no results')
+ return number
+
+ def page(self, number):
+ """
+ Returns a Page object for the given 1-based page number.
+ """
+ number = self.validate_number(number)
+ # remove the extra item(s) when creating the page
+ page_items = self.object_list[:self.per_page]
+ return FinitePage(page_items, number, self)
+
+
+class FinitePage(InfinitePage):
+
+ def has_next(self):
+ """
+ Checks for one more item than last on this page.
+ """
+ try:
+ self.paginator.object_list[self.paginator.per_page]
+ except IndexError:
+ return False
+ return True
+
+ def start_index(self):
+ """
+ Returns the 1-based index of the first object on this page,
+ relative to total objects in the paginator.
+ """
+ ## TODO should this holler if you haven't defined the offset?
+ return self.paginator.offset
--- /dev/null
+# Copyright (c) 2008, Eric Florenzano
+# Copyright (c) 2010, 2011 Linaro Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the author nor the names of other
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+from django.conf import settings
+
+
+DEFAULT_PAGINATION = getattr(
+ settings, 'PAGINATION_DEFAULT_PAGINATION', 20)
+DEFAULT_WINDOW = getattr(
+ settings, 'PAGINATION_DEFAULT_WINDOW', 4)
+DEFAULT_MARGIN = getattr(
+ settings, 'PAGINATION_DEFAULT_MARGIN', DEFAULT_WINDOW)
+DEFAULT_ORPHANS = getattr(
+ settings, 'PAGINATION_DEFAULT_ORPHANS', 0)
+INVALID_PAGE_RAISES_404 = getattr(
+ settings, 'PAGINATION_INVALID_PAGE_RAISES_404', False)
+DISPLAY_PAGE_LINKS = getattr(
+ settings, 'PAGINATION_DISPLAY_PAGE_LINKS', True)
+PREVIOUS_LINK_DECORATOR = getattr(
+ settings, 'PAGINATION_PREVIOUS_LINK_DECORATOR', "‹‹ ")
+NEXT_LINK_DECORATOR = getattr(
+ settings, 'PAGINATION_NEXT_LINK_DECORATOR', " ››")
+DISPLAY_DISABLED_PREVIOUS_LINK = getattr(
+ settings, 'PAGINATION_DISPLAY_DISABLED_PREVIOUS_LINK', False)
+DISPLAY_DISABLED_NEXT_LINK = getattr(
+ settings, 'PAGINATION_DISPLAY_DISABLED_NEXT_LINK', False)
+DISABLE_LINK_FOR_FIRST_PAGE = getattr(
+ settings, 'PAGINATION_DISABLE_LINK_FOR_FIRST_PAGE', True)
--- /dev/null
+{% if is_paginated %}
+{% load i18n %}
+<div class="pagination">
+ {% block previouslink %}
+ {% if page_obj.has_previous %}
+ {% if disable_link_for_first_page and page_obj.previous_page_number == 1 %}
+ <a href="{{ request.path }}{% if getvars %}?{{ getvars|slice:"1:" }}{% endif %}" class="prev">{{ previous_link_decorator|safe }}{% trans "previous" %}</a>
+ {% else %}
+ <a href="?page{{ page_suffix }}={{ page_obj.previous_page_number }}{{ getvars }}" class="prev">{{ previous_link_decorator|safe }}{% trans "previous" %}</a>
+ {% endif %}
+ {% else %}
+ {% if display_disabled_previous_link %}
+ <span class="disabled prev">{{ previous_link_decorator|safe }}{% trans "previous" %}</span>
+ {% endif %}
+ {% endif %}
+ {% endblock previouslink %}
+ {% block pagelinks %}
+ {% if display_page_links %}
+ {% for page in pages %}
+ {% if page %}
+ {% ifequal page page_obj.number %}
+ <span class="current page">{{ page }}</span>
+ {% else %}
+ {% if disable_link_for_first_page and page == 1 %}
+ <a href="{{ request.path }}{% if getvars %}?{{ getvars|slice:"1:" }}{% endif %}" class="page">{{ page }}</a>
+ {% else %}
+ <a href="?page{{ page_suffix }}={{ page }}{{ getvars }}" class="page">{{ page }}</a>
+ {% endif %}
+ {% endifequal %}
+ {% else %}
+ ...
+ {% endif %}
+ {% endfor %}
+ {% endif %}
+ {% endblock pagelinks %}
+ {% block nextlink %}
+ {% if page_obj.has_next %}
+ <a href="?page{{ page_suffix }}={{ page_obj.next_page_number }}{{ getvars }}" class="next">{% trans "next" %}{{ next_link_decorator|safe }}</a>
+ {% else %}
+ {% if display_disabled_next_link %}
+ <span class="disabled next">{% trans "next" %}{{ next_link_decorator|safe }}</span>
+ {% endif %}
+ {% endif %}
+ {% endblock nextlink %}
+</div>
+{% endif %}
--- /dev/null
+# Copyright (c) 2008, Eric Florenzano
+# Copyright (c) 2010, 2011 Linaro Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the author nor the names of other
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+from django.conf import settings
+from django.core.exceptions import ImproperlyConfigured
+from django.core.paginator import Paginator, InvalidPage
+from django.http import Http404
+from django.template import (
+ Context,
+ Library,
+ Node,
+ TemplateSyntaxError,
+ Variable,
+ loader,
+)
+
+try:
+ from django.template.base import TOKEN_BLOCK
+except ImportError: # Django < 1.8
+ from django.template import TOKEN_BLOCK
+
+from django.template.loader import select_template
+from django.utils.text import unescape_string_literal
+
+# TODO, import this normally later on
+from fnp_django_pagination.settings import *
+
+
+def do_autopaginate(parser, token):
+ """
+ Splits the arguments to the autopaginate tag and formats them correctly.
+
+ Syntax is:
+
+ autopaginate QUERYSET [PAGINATE_BY] [ORPHANS] [as NAME]
+ """
+ # Check whether there are any other autopaginations are later in this template
+ expr = lambda obj: (obj.token_type == TOKEN_BLOCK and \
+ len(obj.split_contents()) > 0 and obj.split_contents()[0] == "autopaginate")
+ multiple_paginations = len([tok for tok in parser.tokens if expr(tok)]) > 0
+
+ i = iter(token.split_contents())
+ paginate_by = None
+ queryset_var = None
+ context_var = None
+ orphans = None
+ word = None
+ try:
+ word = next(i)
+ assert word == "autopaginate"
+ queryset_var = next(i)
+ word = next(i)
+ if word != "as":
+ paginate_by = word
+ try:
+ paginate_by = int(paginate_by)
+ except ValueError:
+ pass
+ word = next(i)
+ if word != "as":
+ orphans = word
+ try:
+ orphans = int(orphans)
+ except ValueError:
+ pass
+ word = next(i)
+ assert word == "as"
+ context_var = next(i)
+ except StopIteration:
+ pass
+ if queryset_var is None:
+ raise TemplateSyntaxError(
+ "Invalid syntax. Proper usage of this tag is: "
+ "{% autopaginate QUERYSET [PAGINATE_BY] [ORPHANS]"
+ " [as CONTEXT_VAR_NAME] %}")
+ return AutoPaginateNode(queryset_var, multiple_paginations, paginate_by, orphans, context_var)
+
+
+class AutoPaginateNode(Node):
+ """
+ Emits the required objects to allow for Digg-style pagination.
+
+ First, it looks in the current context for the variable specified, and using
+ that object, it emits a simple ``Paginator`` and the current page object
+ into the context names ``paginator`` and ``page_obj``, respectively.
+
+ It will then replace the variable specified with only the objects for the
+ current page.
+
+ .. note::
+
+ It is recommended to use *{% paginate %}* after using the autopaginate
+ tag. If you choose not to use *{% paginate %}*, make sure to display the
+ list of available pages, or else the application may seem to be buggy.
+ """
+ def __init__(self, queryset_var, multiple_paginations, paginate_by=None,
+ orphans=None, context_var=None):
+ if paginate_by is None:
+ paginate_by = DEFAULT_PAGINATION
+ if orphans is None:
+ orphans = DEFAULT_ORPHANS
+ self.queryset_var = Variable(queryset_var)
+ if isinstance(paginate_by, int):
+ self.paginate_by = paginate_by
+ else:
+ self.paginate_by = Variable(paginate_by)
+ if isinstance(orphans, int):
+ self.orphans = orphans
+ else:
+ self.orphans = Variable(orphans)
+ self.context_var = context_var
+ self.multiple_paginations = multiple_paginations
+
+ def render(self, context):
+ # Save multiple_paginations state in context
+ if self.multiple_paginations and 'multiple_paginations' not in context:
+ context['multiple_paginations'] = True
+
+ if context.get('multiple_paginations') or getattr(context, "paginator", None):
+ page_suffix = '_%s' % self.queryset_var
+ else:
+ page_suffix = ''
+
+ key = self.queryset_var.var
+ value = self.queryset_var.resolve(context)
+ if isinstance(self.paginate_by, int):
+ paginate_by = self.paginate_by
+ else:
+ paginate_by = self.paginate_by.resolve(context)
+ if isinstance(self.orphans, int):
+ orphans = self.orphans
+ else:
+ orphans = self.orphans.resolve(context)
+ paginator = Paginator(value, paginate_by, orphans)
+ try:
+ request = context['request']
+ except KeyError:
+ raise ImproperlyConfigured(
+ "You need to enable 'django.core.context_processors.request'."
+ " See linaro-django-pagination/README file for TEMPLATE_CONTEXT_PROCESSORS details")
+ try:
+ page_obj = paginator.page(request.page(page_suffix))
+ except InvalidPage:
+ if INVALID_PAGE_RAISES_404:
+ raise Http404('Invalid page requested. If DEBUG were set to ' +
+ 'False, an HTTP 404 page would have been shown instead.')
+ context[key] = []
+ context['invalid_page'] = True
+ return ''
+ if self.context_var is not None:
+ context[self.context_var] = page_obj.object_list
+ else:
+ context[key] = page_obj.object_list
+ context['paginator'] = paginator
+ context['page_obj'] = page_obj
+ context['page_suffix'] = page_suffix
+ return ''
+
+
+class PaginateNode(Node):
+
+ def __init__(self, template=None):
+ self.template = template
+
+ def render(self, context):
+ template_list = ['pagination/pagination.html']
+ new_context = paginate(context)
+ if self.template:
+ template_list.insert(0, self.template)
+ return loader.render_to_string(template_list, new_context,
+ context_instance = context)
+
+
+
+def do_paginate(parser, token):
+ """
+ Emits the pagination control for the most recent autopaginate list
+
+ Syntax is:
+
+ paginate [using "TEMPLATE"]
+
+ Where TEMPLATE is a quoted template name. If missing the default template
+ is used (paginate/pagination.html).
+ """
+ argv = token.split_contents()
+ argc = len(argv)
+ if argc == 1:
+ template = None
+ elif argc == 3 and argv[1] == 'using':
+ template = unescape_string_literal(argv[2])
+ else:
+ raise TemplateSyntaxError(
+ "Invalid syntax. Proper usage of this tag is: "
+ "{% paginate [using \"TEMPLATE\"] %}")
+ return PaginateNode(template)
+
+
+def paginate(context, window=DEFAULT_WINDOW, margin=DEFAULT_MARGIN):
+ """
+ Renders the ``pagination/pagination.html`` template, resulting in a
+ Digg-like display of the available pages, given the current page. If there
+ are too many pages to be displayed before and after the current page, then
+ elipses will be used to indicate the undisplayed gap between page numbers.
+
+ Requires one argument, ``context``, which should be a dictionary-like data
+ structure and must contain the following keys:
+
+ ``paginator``
+ A ``Paginator`` or ``QuerySetPaginator`` object.
+
+ ``page_obj``
+ This should be the result of calling the page method on the
+ aforementioned ``Paginator`` or ``QuerySetPaginator`` object, given
+ the current page.
+
+ This same ``context`` dictionary-like data structure may also include:
+
+ ``getvars``
+ A dictionary of all of the **GET** parameters in the current request.
+ This is useful to maintain certain types of state, even when requesting
+ a different page.
+
+ Argument ``window`` is number to pages before/after current page. If window
+ exceeds pagination border (1 and end), window is moved to left or right.
+
+ Argument ``margin``` is number of pages on start/end of pagination.
+ Example:
+ window=2, margin=1, current=6 1 ... 4 5 [6] 7 8 ... 11
+ window=2, margin=0, current=1 [1] 2 3 4 5 ...
+ window=2, margin=0, current=5 ... 3 4 [5] 6 7 ...
+ window=2, margin=0, current=11 ... 7 8 9 10 [11]
+ """
+
+ if window < 0:
+ raise ValueError('Parameter "window" cannot be less than zero')
+ if margin < 0:
+ raise ValueError('Parameter "margin" cannot be less than zero')
+ try:
+ paginator = context['paginator']
+ page_obj = context['page_obj']
+ page_suffix = context.get('page_suffix', '')
+ page_range = list(paginator.page_range)
+ # Calculate the record range in the current page for display.
+ records = {'first': 1 + (page_obj.number - 1) * paginator.per_page}
+ records['last'] = records['first'] + paginator.per_page - 1
+ if records['last'] + paginator.orphans >= paginator.count:
+ records['last'] = paginator.count
+
+ # figure window
+ window_start = page_obj.number - window - 1
+ window_end = page_obj.number + window
+
+ # solve if window exceeded page range
+ if window_start < 0:
+ window_end = window_end - window_start
+ window_start = 0
+ if window_end > paginator.num_pages:
+ window_start = max(0, window_start - (window_end - paginator.num_pages))
+ window_end = paginator.num_pages
+ pages = page_range[window_start:window_end]
+
+ # figure margin and add elipses
+ if margin > 0:
+ # figure margin
+ tmp_pages = set(pages)
+ tmp_pages = tmp_pages.union(page_range[:margin])
+ tmp_pages = tmp_pages.union(page_range[-margin:])
+ tmp_pages = list(tmp_pages)
+ tmp_pages.sort()
+ pages = []
+ pages.append(tmp_pages[0])
+ for i in range(1, len(tmp_pages)):
+ # figure gap size => add elipses or fill in gap
+ gap = tmp_pages[i] - tmp_pages[i - 1]
+ if gap >= 3:
+ pages.append(None)
+ elif gap == 2:
+ pages.append(tmp_pages[i] - 1)
+ pages.append(tmp_pages[i])
+ else:
+ if pages[0] != 1:
+ pages.insert(0, None)
+ if pages[-1] != paginator.num_pages:
+ pages.append(None)
+
+ new_context = {
+ 'MEDIA_URL': settings.MEDIA_URL,
+ 'STATIC_URL': getattr(settings, "STATIC_URL", None),
+ 'disable_link_for_first_page': DISABLE_LINK_FOR_FIRST_PAGE,
+ 'display_disabled_next_link': DISPLAY_DISABLED_NEXT_LINK,
+ 'display_disabled_previous_link': DISPLAY_DISABLED_PREVIOUS_LINK,
+ 'display_page_links': DISPLAY_PAGE_LINKS,
+ 'is_paginated': paginator.count > paginator.per_page,
+ 'next_link_decorator': NEXT_LINK_DECORATOR,
+ 'page_obj': page_obj,
+ 'page_suffix': page_suffix,
+ 'pages': pages,
+ 'paginator': paginator,
+ 'previous_link_decorator': PREVIOUS_LINK_DECORATOR,
+ 'records': records,
+ }
+ if 'request' in context:
+ getvars = context['request'].GET.copy()
+ if 'page%s' % page_suffix in getvars:
+ del getvars['page%s' % page_suffix]
+ if len(getvars.keys()) > 0:
+ new_context['getvars'] = "&%s" % getvars.urlencode()
+ else:
+ new_context['getvars'] = ''
+ return new_context
+ except (KeyError, AttributeError):
+ return {}
+
+
+register = Library()
+register.tag('paginate', do_paginate)
+register.tag('autopaginate', do_autopaginate)
--- /dev/null
+{% extends "django_testproject/base.html" %}
+{% load pagination_tags %}
+
+
+{% block content %}
+<p>This page demonstrates how autopaginate behaves under certain conditions</p>
+<p>Below you can see a list of {{ item_list|length }} items.</p>
+{% autopaginate item_list %}
+{% for item in item_list %}
+<p>Item {{item}}</p>
+{% endfor %}
+{% paginate %}
+{% endblock %}
--- /dev/null
+{% extends "django_testproject/base.html" %}
+{% load pagination_tags %}
+
+
+{% block content %}
+<p>This page demonstrates how autopaginate behaves under certain conditions</p>
+<p>Below you can see two lists.</p>
+<p>First list has {{ first_item_list|length }} items.</p>
+{% autopaginate first_item_list 5 %}
+{% for item in first_item_list %}
+<p>{{item}}</p>
+{% endfor %}
+{% paginate using "pagination/custom_pagination.html" %}
+
+<p>Second list has {{ second_item_list|length}} items.</p>
+{% autopaginate second_item_list 5 %}
+{% paginate %}
+{% for item in second_item_list %}
+<p>{{item}}</p>
+{% endfor %}
+{% endblock %}
--- /dev/null
+{% extends "pagination/pagination.html" %}
+
+
+{% block previouslink %}
+ <p style="color: red; background-color: white;">This part is custom</p>
+ {{ block.super }}
+{% endblock previouslink %}
--- /dev/null
+# Copyright (c) 2010, 2011 Linaro Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the author nor the names of other
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+from django.conf.urls.defaults import (
+ patterns, url, include, handler500, handler404)
+
+urlpatterns = patterns(
+ 'example.views',
+ url(r'^list/$', 'list'),
+ url(r'^complex-list/$', 'complex_list'))
--- /dev/null
+# Copyright (c) 2010, 2011 Linaro Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the author nor the names of other
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+
+
+def list(request):
+ return render_to_response("example/list.html", {
+ 'item_list': range(1000),
+ }, RequestContext(request))
+
+
+def complex_list(request):
+ return render_to_response("example/two_lists.html", {
+ 'first_item_list': ["first list item %d" % item for item in range(1000)],
+ 'second_item_list': ["second list item %d" % item for item in range(1000)],
+ }, RequestContext(request))
--- /dev/null
+#!/usr/bin/env python
+# Copyright (c) 2010, 2011 Linaro Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the author nor the names of other
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import logging
+
+from django.core.management import execute_manager
+
+try:
+ from fnp_django_pagination.test_project import settings
+except ImportError as ex:
+ logging.exception("Unable to import application settings")
+ raise SystemExit(ex)
+
+
+if __name__ == "__main__":
+ execute_manager(settings)
--- /dev/null
+# Copyright (c) 2010, 2011 Linaro Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the author nor the names of other
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import sys
+import os
+
+# Add this directory to path so that 'example' can be imported later
+# below. Without this the runner will fail when started via ``setup.py
+# test``
+sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
+
+from django_testproject.settings import gen_settings
+
+
+locals().update(
+ gen_settings(
+ INSTALLED_APPS=[
+ 'example',
+ 'fnp_django_pagination'],
+ MIDDLEWARE_CLASSES=[
+ 'fnp_django_pagination.middleware.PaginationMiddleware'],
+ TEMPLATE_CONTEXT_PROCESSORS=[
+ # Request processor needs to be enabled
+ 'django.core.context_processors.request'],
+ ROOT_URLCONF="fnp_django_pagination.test_project.urls"),
+ TEMPLATE_LOADERS = ['django.template.loaders.app_directories.Loader'],
+ SECRET_KEY = 'not for production',
+ )
--- /dev/null
+# Copyright (c) 2010, 2011 Linaro Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the author nor the names of other
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+def run_tests():
+ from django_testproject.tests import run_tests_for
+ run_tests_for("fnp_django_pagination.test_project.settings")
+
+
+if __name__ == '__main__':
+ run_tests()
--- /dev/null
+# Copyright (c) 2010, 2011 Linaro Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the author nor the names of other
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+from django.conf.urls.defaults import (
+ patterns, url, include, handler500, handler404)
+
+# Empty patterns so that test project can be started and would work normally
+urlpatterns = patterns('', url('', include('example.urls')))
--- /dev/null
+from .test_main import *
--- /dev/null
+#!/usr/bin/env python
+
+import django
+import os
+import sys
+
+from django.core.management import call_command
+
+
+def runtests():
+ os.environ['DJANGO_SETTINGS_MODULE'] = 'fnp_django_pagination.tests.settings'
+
+ try:
+ django.setup()
+ except AttributeError: # for Django 1.6 compatible
+ pass
+
+ failures = call_command('test', 'fnp_django_pagination')
+ sys.exit(bool(failures))
+
+if __name__ == '__main__':
+ runtests()
--- /dev/null
+DATABASES = {
+ 'default': {
+ 'NAME': ':memory:',
+ 'ENGINE': 'django.db.backends.sqlite3',
+ }
+}
+
+SECRET_KEY = 'fake-key'
+
+INSTALLED_APPS = (
+ 'fnp_django_pagination',
+)
--- /dev/null
+# Copyright (c) 2008, Eric Florenzano
+# Copyright (c) 2010, 2011 Linaro Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the author nor the names of other
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from django.core.paginator import Paginator
+from django.http import HttpRequest as DjangoHttpRequest
+from django.template import Template, Context
+
+try:
+ from django.test import SimpleTestCase
+except ImportError: # Django 1.2 compatible
+ from django.test import TestCase as SimpleTestCase
+
+from fnp_django_pagination.paginator import InfinitePaginator, FinitePaginator
+from fnp_django_pagination.templatetags.pagination_tags import paginate
+from fnp_django_pagination.middleware import PaginationMiddleware
+
+
+class HttpRequest(DjangoHttpRequest):
+ page = lambda self, suffix: 1
+
+
+class CommonTestCase(SimpleTestCase):
+ def test_records_for_the_first_page(self):
+ p = Paginator(range(15), 2)
+ pg = paginate({'paginator': p, 'page_obj': p.page(1)})
+ self.assertListEqual(pg['pages'], [1, 2, 3, 4, 5, 6, 7, 8])
+ self.assertEqual(pg['records']['first'], 1)
+ self.assertEqual(pg['records']['last'], 2)
+
+ def test_records_for_the_last_page(self):
+ p = Paginator(range(15), 2)
+ pg = paginate({'paginator': p, 'page_obj': p.page(8)})
+ self.assertListEqual(pg['pages'], [1, 2, 3, 4, 5, 6, 7, 8])
+ self.assertEqual(pg['records']['first'], 15)
+ self.assertEqual(pg['records']['last'], 15)
+
+ def test_pages_list(self):
+ p = Paginator(range(17), 2)
+ self.assertEqual(paginate({'paginator': p, 'page_obj': p.page(1)})['pages'], [1, 2, 3, 4, 5, 6, 7, 8, 9])
+
+ def test_page_with_empty_objects_list(self):
+ p = Paginator(range(0), 2)
+ self.assertListEqual(paginate({'paginator': p, 'page_obj': p.page(1)})['pages'], [1])
+
+
+class DefaultWindowTestCase(SimpleTestCase):
+ """
+ Test paginate using default window setting
+ moving the window from 1 ... to end
+ window size = 2, margin = 2
+ window = 2 -> show 5 pages
+ """
+ def setUp(self):
+ self.p = Paginator(range(31), 2)
+
+ def test_on_start_page_1(self):
+ # [1] 2 3 4 5 ... 15, 16
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(1)}, 2, 2)['pages'],
+ [1, 2, 3, 4, 5, None, 15, 16]
+ )
+
+ def test_on_start_page_2(self):
+ # 1 [2] 3 4 5 ... 15, 16
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(2)}, 2, 2)['pages'],
+ [1, 2, 3, 4, 5, None, 15, 16]
+ )
+
+ def test_on_start_page_3(self):
+ # 1 2 [3] 4 5 ... 15, 16
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(3)}, 2, 2)['pages'],
+ [1, 2, 3, 4, 5, None, 15, 16]
+ )
+
+ def test_on_start_page_4(self):
+ # 1 2 3 [4] 5 6 ... 15, 16
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(4)}, 2, 2)['pages'],
+ [1, 2, 3, 4, 5, 6, None, 15, 16])
+
+ def test_on_start_page_5(self):
+ # 1 2 3 4 [5] 6 7 ... 15, 16
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(5)}, 2, 2)['pages'],
+ [1, 2, 3, 4, 5, 6, 7, None, 15, 16]
+ )
+
+ def test_in_middle(self):
+ # 1 2 ... 5 6 [7] 8 9 ... 15, 16
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(7)}, 2, 2)['pages'],
+ [1, 2, None, 5, 6, 7, 8, 9, None, 15, 16]
+ )
+
+ def test_on_end_page_13(self):
+ # 1 2 ... 12 [13] 14 15 16
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(13)}, 2, 2)['pages'],
+ [1, 2, None, 11, 12, 13, 14, 15, 16],
+ )
+
+ def test_on_end(self):
+ # 1 2 ... 12 13 14 15 [16
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(16)}, 2, 2)['pages'],
+ [1, 2, None, 12, 13, 14, 15, 16]
+ )
+
+
+class NoMarginTestCase(SimpleTestCase):
+ def setUp(self):
+ self.p = Paginator(range(31), 2)
+
+ def test_on_start(self):
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(3)}, 2, 0)['pages'],
+ [1, 2, 3, 4, 5, None],
+ )
+
+ def test_in_middle(self):
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(5)}, 2, 0)['pages'],
+ [None, 3, 4, 5, 6, 7, None],
+ )
+
+ def test_on_end(self):
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(16)}, 2, 0)['pages'],
+ [None, 12, 13, 14, 15, 16],
+ )
+
+
+class ZeroWindowZeroMarginTestCase(SimpleTestCase):
+ """
+ Test paginate using window=0 and margin=0
+ """
+ def setUp(self):
+ self.p = Paginator(range(31), 2)
+
+ def test_on_start_page_1(self):
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(1)}, 0, 0)['pages'],
+ [1, None],
+ )
+
+ def test_in_middle_page_2(self):
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(2)}, 0, 0)['pages'],
+ [None, 2, None],
+ )
+
+ def test_in_middle_page_3(self):
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(3)}, 0, 0)['pages'],
+ [None, 3, None],
+ )
+
+ def test_in_middle_page_10(self):
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(10)}, 0, 0)['pages'],
+ [None, 10, None],
+ )
+
+ def test_in_middle_page_14(self):
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(14)}, 0, 0)['pages'],
+ [None, 14, None],
+ )
+
+ def test_in_middle_page_15(self):
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(15)}, 0, 0)['pages'],
+ [None, 15, None],
+ )
+
+ def test_on_end_page_16(self):
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(16)}, 0, 0)['pages'],
+ [None, 16],
+ )
+
+
+class NoEllipsisTestCase(SimpleTestCase):
+ """
+ Tests a case where should be no any ellipsis pages.
+ """
+ def setUp(self):
+ self.p = Paginator(range(100), 25)
+
+ def test_on_start(self):
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(1)}, 2, 0)['pages'],
+ [1, 2, 3, 4],
+ )
+
+ def test_in_middle_page_2(self):
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(2)}, 2, 0)['pages'],
+ [1, 2, 3, 4],
+ )
+
+ def test_in_middle_page_3(self):
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(3)}, 2, 0)['pages'],
+ [1, 2, 3, 4],
+ )
+
+ def test_on_end(self):
+ self.assertListEqual(
+ paginate({'paginator': self.p, 'page_obj': self.p.page(4)}, 2, 0)['pages'],
+ [1, 2, 3, 4],
+ )
+
+
+class SpecialTestCase(SimpleTestCase):
+ def test_middle_with_no_window_and_margin_1(self):
+ p = Paginator(range(31), 2)
+ self.assertListEqual(
+ paginate({'paginator': p, 'page_obj': p.page(5)}, 0, 1)['pages'],
+ [1, None, 5, None, 16],
+ )
+
+ def test_middle_with_no_window_and_margin_4(self):
+ p = Paginator(range(21), 2, 1)
+ self.assertListEqual(
+ paginate({'paginator': p, 'page_obj': p.page(1)}, 0, 4)['pages'],
+ [1, 2, 3, 4, None, 7, 8, 9, 10],
+ )
+
+
+class TemplateRenderingTestCase(SimpleTestCase):
+ def test_default_tag_options(self):
+ t = Template("{% load pagination_tags %}{% autopaginate var %}{% paginate %}")
+ self.assertIn(
+ '<div class="pagination">',
+ t.render(Context({'var': range(21), 'request': HttpRequest()})),
+ )
+
+ def test_paginate_by_option(self):
+ t = Template("{% load pagination_tags %}{% autopaginate var 20 %}{% paginate %}")
+ self.assertIn(
+ '<div class="pagination">',
+ t.render(Context({'var': range(21), 'request': HttpRequest()})),
+ )
+
+ def test_orphans_option(self):
+ t = Template("{% load pagination_tags %}{% autopaginate var by %}{% paginate %}")
+ content = t.render(Context({'var': range(21), 'by': 20, 'request': HttpRequest()}))
+ self.assertIn('<div class="pagination">', content)
+ self.assertIn('<a href="?page=2"', content)
+
+ def test_as_option(self):
+ t = Template("{% load pagination_tags %}{% autopaginate var by as foo %}{{ foo }}")
+ self.assertEqual(
+ t.render(Context({'var': range(21), 'by': 20, 'request': HttpRequest()})),
+ str(range(20)),
+ )
+
+ def test_multiple_pagination(self):
+ t = Template("{% load pagination_tags %}{% autopaginate var2 by as foo2 %}{% paginate %}"
+ "{% autopaginate var by as foo %}{% paginate %}")
+ content = t.render(Context({'var': range(21), 'var2': range(50, 121), 'by': 20, 'request': HttpRequest()}))
+ self.assertIn('<div class="pagination">', content)
+ self.assertIn('<a href="?page_var2=2"', content)
+ self.assertIn('<a href="?page_var=2"', content)
+
+
+class InfinitePaginatorTestCase(SimpleTestCase):
+ def setUp(self):
+ self.p = InfinitePaginator(range(20), 2, link_template='/bacon/page/%d')
+
+ def test_paginator_repr(self):
+ self.assertEqual(
+ repr(InfinitePaginator),
+ "<class 'fnp_django_pagination.paginator.InfinitePaginator'>",
+ )
+
+ def test_validate_number(self):
+ self.assertEqual(self.p.validate_number(2), 2)
+
+ def test_orphans(self):
+ self.assertEqual(self.p.orphans, 0)
+
+ def test_page_repr(self):
+ self.assertEqual(repr(self.p.page(3)), '<Page 3>')
+
+ def test_page_end_index(self):
+ self.assertEqual(self.p.page(3).end_index(), 6)
+
+ def test_page_has_next(self):
+ self.assertTrue(self.p.page(3).has_next(), True)
+
+ def test_page_has_previous(self):
+ self.assertTrue(self.p.page(3).has_previous(), True)
+
+ def test_page_next_link(self):
+ self.assertEqual(self.p.page(3).next_link(), '/bacon/page/4')
+
+ def test_page_previous_link(self):
+ self.assertEqual(self.p.page(3).previous_link(), '/bacon/page/2')
+
+ def test_last_page_which_has_no_next_page(self):
+ self.assertFalse(self.p.page(10).has_next())
+
+ def test_first_page_which_has_no_previous_page(self):
+ self.assertFalse(self.p.page(1).has_previous())
+
+
+class FinitePaginatorTestCase(SimpleTestCase):
+ def setUp(self):
+ self.p = FinitePaginator(range(20), 2, offset=10, link_template='/bacon/page/%d')
+
+ def test_repr(self):
+ self.assertEqual(
+ repr(FinitePaginator),
+ "<class 'fnp_django_pagination.paginator.FinitePaginator'>"
+ )
+
+ def test_validate_number(self):
+ self.assertEqual(self.p.validate_number(2), 2)
+
+ def test_orphans(self):
+ self.assertEqual(self.p.orphans, 0)
+
+ def test_page_repr(self):
+ self.assertEqual(repr(self.p.page(3)), '<Page 3>')
+
+ def test_page_start_index(self):
+ self.assertEqual(self.p.page(3).start_index(), 10)
+
+ def test_page_end(self):
+ self.assertEqual(self.p.page(3).end_index(), 6)
+
+ def test_page_has_next(self):
+ self.assertTrue(self.p.page(3).has_next(), True)
+
+ def test_page_has_previous(self):
+ self.assertTrue(self.p.page(3).has_previous(), True)
+
+ def test_page_next_link(self):
+ self.assertEqual(self.p.page(3).next_link(), '/bacon/page/4')
+
+ def test_page_previous_link(self):
+ self.assertEqual(self.p.page(3).previous_link(), '/bacon/page/2')
+
+ def test_on_start_page_repr(self):
+ self.assertEqual(repr(self.p.page(2)), '<Page 2>')
+
+ def test_on_start_has_no_next(self):
+ self.assertTrue(self.p.page(2).has_next(), False)
+
+ def test_on_start_has_previous(self):
+ self.assertTrue(self.p.page(2).has_previous(), True)
+
+ def test_on_start_has_next_link(self):
+ self.assertEqual(self.p.page(2).next_link(), '/bacon/page/3')
+
+ def test_on_start_has_previous_link(self):
+ self.assertEqual(self.p.page(2).previous_link(), '/bacon/page/1')
+
+
+class MiddlewareTestCase(SimpleTestCase):
+ """
+ Test middleware
+ """
+ def test_get_page_in_request(self):
+ middleware = PaginationMiddleware()
+ request = DjangoHttpRequest()
+ middleware.process_request(request)
+ self.assertEqual(request.page(''), 1)
+++ /dev/null
-# Copyright (c) 2008, Eric Florenzano
-# Copyright (c) 2010, 2011 Linaro Limited
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of the author nor the names of other
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""
-linaro-django-pagination is a set of utilities for creating robust pagination
-tools throughout a django application.
-"""
-
-
-__version__ = (2, 0, 2, "final", 0)
+++ /dev/null
-# Deutch translation of linaro-django-pagination
-# Copyright (c) 2009, linaro-django-pagination team
-# This file is distributed under the same license as the linaro-django-pagination package.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: linaro-django-pagination master\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-03-16 16:26+0100\n"
-"PO-Revision-Date: 2012-01-26 13:27+0100\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: templates/pagination/pagination.html:5
-#: templates/pagination/pagination.html:7
-msgid "previous"
-msgstr "Zurück"
-
-#: templates/pagination/pagination.html:21
-#: templates/pagination/pagination.html:23
-msgid "next"
-msgstr "Weiter"
+++ /dev/null
-# Spanish translation of django-pagination
-# Copyright (c) 2010, Miguel Araujo
-# This file is distributed under the same license as the django-pagination package.
-# Miguel Araujo <miguel.araujo.perez@gmail.com>, 2010
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: linaro-django-pagination master\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-09-16 16:32+0200\n"
-"PO-Revision-Date: 2012-01-26 13:24+0100\n"
-"Last-Translator: Miguel Araujo <miguel.araujo.perez@gmail.com>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-
-#: templates/pagination/pagination.html:5
-#: templates/pagination/pagination.html:7
-msgid "previous"
-msgstr "anterior"
-
-#: templates/pagination/pagination.html:21
-#: templates/pagination/pagination.html:23
-msgid "next"
-msgstr "siguiente"
+++ /dev/null
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2013-07-11 12:51+0000\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"Language: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-
-#: templates/pagination/pagination.html:6
-#: templates/pagination/pagination.html:9
-msgid "previous"
-msgstr "edellinen"
-
-#: templates/pagination/pagination.html:30
-#: templates/pagination/pagination.html:33
-msgid "next"
-msgstr "seuraava"
+++ /dev/null
-# French translation of linaro-django-pagination
-# Copyright (c) 2008, Julien Demoor
-# This file is distributed under the same license as the linaro-django-pagination package.
-# Julien Demoor <julien@jdemoor.com>, 2008
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: linaro-django-pagination master\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-10-24 00:41-0700\n"
-"PO-Revision-Date: 2012-01-26 13:25+0100\n"
-"Last-Translator: Julien Demoor <julien@jdemoor.com>\n"
-"Language-Team: French\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: templates/pagination/pagination.html:5
-#: templates/pagination/pagination.html:7
-msgid "previous"
-msgstr "précédente"
-
-#: templates/pagination/pagination.html:21
-#: templates/pagination/pagination.html:23
-msgid "next"
-msgstr "suivante"
+++ /dev/null
-# django-pagination Italian translation
-# Copyright (c) 2010 Fabio Corneti <info@corneti.com>
-# This file is distributed under the same license as the django-pagination package.
-# Fabio Corneti <info@corneti.com>, 2010.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: linaro-django-pagination-master\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-04-22 12:04+0200\n"
-"PO-Revision-Date: 2012-01-26 11:26+0100\n"
-"Last-Translator: Fabio Corneti <info@corneti.com>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: templates/pagination/default.html:6 templates/pagination/default.html:9
-msgid "previous"
-msgstr "precedenti"
-
-#: templates/pagination/default.html:30 templates/pagination/default.html:33
-msgid "next"
-msgstr "successive"
+++ /dev/null
-# Norwegian translation of linaro-django-pagination.
-# Copyright (c) 2008, linaro-django-pagination team
-# This file is distributed under the same license as the linaro-django-pagination package.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: linaro-django-pagination master\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-03-28 10:48+0200\n"
-"PO-Revision-Date: 2012-01-26 11:32+0100\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: templates/pagination/pagination.html:5
-#: templates/pagination/pagination.html:7
-msgid "previous"
-msgstr "Førre"
-
-#: templates/pagination/pagination.html:21
-#: templates/pagination/pagination.html:23
-msgid "next"
-msgstr "Neste"
+++ /dev/null
-# SOME DESCRIPTIVE TITLE.
-# Copyright (c) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-03-28 10:48+0200\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: templates/pagination/pagination.html:5
-#: templates/pagination/pagination.html:7
-msgid "previous"
-msgstr "Forrige"
-
-#: templates/pagination/pagination.html:21
-#: templates/pagination/pagination.html:23
-msgid "next"
-msgstr "Neste"
+++ /dev/null
-# Polish translation of linaro-django-pagination.
-# Copyright (c) 2008, linaro-django-pagination team
-# This file is distributed under the same license as the linaro-django-pagination package.
-# Jarek Zgoda <jarek.zgoda@gmail.com>, 2008.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: 1.0\n"
-"Report-Msgid-Bugs-To: linaro-django-pagination master\n"
-"POT-Creation-Date: 2008-10-24 00:41-0700\n"
-"PO-Revision-Date: 2012-01-26 11:29+0100\n"
-"Last-Translator: Jarek Zgoda <jarek.zgoda@gmail.com>\n"
-"Language-Team: PL <pl@li.org>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: templates/pagination/pagination.html:5
-#: templates/pagination/pagination.html:7
-msgid "previous"
-msgstr "poprzednia"
-
-#: templates/pagination/pagination.html:21
-#: templates/pagination/pagination.html:23
-msgid "next"
-msgstr "następna"
+++ /dev/null
-# linaro-django-pagination Portuguese translation.
-# Copyright (c) 2008, Alcides Fonseca
-# http://alcidesfonseca.com
-# This file is distributed under the WTFPL
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: linaro-django-pagination master\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-10-24 00:41-0700\n"
-"PO-Revision-Date: 2012-01-26 11:26+0100\n"
-"Last-Translator: Alcides Fonseca <me@alcidesfonseca.com>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: templates/pagination/pagination.html:5
-#: templates/pagination/pagination.html:7
-msgid "previous"
-msgstr "anterior"
-
-#: templates/pagination/pagination.html:21
-#: templates/pagination/pagination.html:23
-msgid "next"
-msgstr "próximo"
+++ /dev/null
-# Portuguese (Brazil) translation of django-pagination
-# Copyright (c) 2011, Tiago Samaha Cordeiro
-# This file is distributed under the same license as the django-pagination package.
-# Tiago Samaha Cordeiro <tiagosamaha@gmail.com>, 2011.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: linaro-django-pagination master\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-01-16 22:06-0200\n"
-"PO-Revision-Date: 2012-01-26 13:28+0100\n"
-"Last-Translator: Tiago Samaha Cordeiro <tiagosamaha@gmail.com>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"Language: Portuguese Brazil\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-
-#: templates/pagination/pagination.html:5
-#: templates/pagination/pagination.html:7
-msgid "previous"
-msgstr "anterior"
-
-#: templates/pagination/pagination.html:21
-#: templates/pagination/pagination.html:23
-msgid "next"
-msgstr "próximo"
+++ /dev/null
-# SOME DESCRIPTIVE TITLE.
-# Copyright (c) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-07-11 16:14+0600\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-
-#: templates/pagination/pagination.html:5
-#: templates/pagination/pagination.html:7
-msgid "previous"
-msgstr "Предыдущая"
-
-#: templates/pagination/pagination.html:21
-#: templates/pagination/pagination.html:23
-msgid "next"
-msgstr "Следующая"
+++ /dev/null
-# Turkish translation of linaro-django-pagination.
-# Copyright (c) 2008, linaro-django-pagination team
-# This file is distributed under the same license as the linaro-django-pagination package.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: linaro-django-pagination master\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-03-16 16:26+0100\n"
-"PO-Revision-Date: 2012-01-26 11:29+0100\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: templates/pagination/pagination.html:5
-#: templates/pagination/pagination.html:7
-msgid "previous"
-msgstr "Önceki"
-
-#: templates/pagination/pagination.html:21
-#: templates/pagination/pagination.html:23
-msgid "next"
-msgstr "Sonraki"
+++ /dev/null
-# Copyright (c) 2008, Eric Florenzano
-# Copyright (c) 2010, 2011 Linaro Limited
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of the author nor the names of other
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-def get_page(self, suffix):
- """
- A function which will be monkeypatched onto the request to get the current
- integer representing the current page.
- """
- try:
- # REQUEST is deprecated as of Django 1.7.
- key = 'page%s' % suffix
- value = self.POST.get(key)
- if value is None:
- value = self.GET.get(key)
- return int(value)
- except (KeyError, ValueError, TypeError):
- return 1
-
-
-class PaginationMiddleware(object):
- """
- Inserts a variable representing the current page onto the request object if
- it exists in either **GET** or **POST** portions of the request.
- """
- def process_request(self, request):
- request.__class__.page = get_page
+++ /dev/null
-# Copyright (c) 2008, Eric Florenzano
-# Copyright (c) 2010, 2011 Linaro Limited
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of the author nor the names of other
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-from django.core.paginator import Paginator, Page, PageNotAnInteger, EmptyPage
-
-
-class InfinitePaginator(Paginator):
- """
- Paginator designed for cases when it's not important to know how many total
- pages. This is useful for any object_list that has no count() method or
- can be used to improve performance for MySQL by removing counts.
-
- The orphans parameter has been removed for simplicity and there's a link
- template string for creating the links to the next and previous pages.
- """
-
- def __init__(self, object_list, per_page, allow_empty_first_page=True,
- link_template='/page/%d/'):
- orphans = 0 # no orphans
- super(InfinitePaginator, self).__init__(object_list, per_page, orphans,
- allow_empty_first_page)
- # no count or num pages
- del self._num_pages, self._count
- # bonus links
- self.link_template = link_template
-
- def validate_number(self, number):
- """
- Validates the given 1-based page number.
- """
- try:
- number = int(number)
- except ValueError:
- raise PageNotAnInteger('That page number is not an integer')
- if number < 1:
- raise EmptyPage('That page number is less than 1')
- return number
-
- def page(self, number):
- """
- Returns a Page object for the given 1-based page number.
- """
- number = self.validate_number(number)
- bottom = (number - 1) * self.per_page
- top = bottom + self.per_page
- page_items = self.object_list[bottom:top]
- # check moved from validate_number
- if not page_items:
- if number == 1 and self.allow_empty_first_page:
- pass
- else:
- raise EmptyPage('That page contains no results')
- return InfinitePage(page_items, number, self)
-
- def _get_count(self):
- """
- Returns the total number of objects, across all pages.
- """
- raise NotImplementedError
- count = property(_get_count)
-
- def _get_num_pages(self):
- """
- Returns the total number of pages.
- """
- raise NotImplementedError
- num_pages = property(_get_num_pages)
-
- def _get_page_range(self):
- """
- Returns a 1-based range of pages for iterating through within
- a template for loop.
- """
- raise NotImplementedError
- page_range = property(_get_page_range)
-
-
-class InfinitePage(Page):
-
- def __repr__(self):
- return '<Page %s>' % self.number
-
- def has_next(self):
- """
- Checks for one more item than last on this page.
- """
- try:
- self.paginator.object_list[self.number * self.paginator.per_page]
- except IndexError:
- return False
- return True
-
- def end_index(self):
- """
- Returns the 1-based index of the last object on this page,
- relative to total objects found (hits).
- """
- return ((self.number - 1) * self.paginator.per_page +
- len(self.object_list))
-
- #Bonus methods for creating links
-
- def next_link(self):
- if self.has_next():
- return self.paginator.link_template % (self.number + 1)
- return None
-
- def previous_link(self):
- if self.has_previous():
- return self.paginator.link_template % (self.number - 1)
- return None
-
-
-class FinitePaginator(InfinitePaginator):
- """
- Paginator for cases when the list of items is already finite.
-
- A good example is a list generated from an API call. This is a subclass
- of InfinitePaginator because we have no idea how many items exist in the
- full collection.
-
- To accurately determine if the next page exists, a FinitePaginator MUST be
- created with an object_list_plus that may contain more items than the
- per_page count. Typically, you'll have an object_list_plus with one extra
- item (if there's a next page). You'll also need to supply the offset from
- the full collection in order to get the page start_index.
-
- This is a very silly class but useful if you love the Django pagination
- conventions.
- """
-
- def __init__(self, object_list_plus, per_page, offset=None,
- allow_empty_first_page=True, link_template='/page/%d/'):
- super(FinitePaginator, self).__init__(object_list_plus, per_page,
- allow_empty_first_page, link_template)
- self.offset = offset
-
- def validate_number(self, number):
- super(FinitePaginator, self).validate_number(number)
- # check for an empty list to see if the page exists
- if not self.object_list:
- if number == 1 and self.allow_empty_first_page:
- pass
- else:
- raise EmptyPage('That page contains no results')
- return number
-
- def page(self, number):
- """
- Returns a Page object for the given 1-based page number.
- """
- number = self.validate_number(number)
- # remove the extra item(s) when creating the page
- page_items = self.object_list[:self.per_page]
- return FinitePage(page_items, number, self)
-
-
-class FinitePage(InfinitePage):
-
- def has_next(self):
- """
- Checks for one more item than last on this page.
- """
- try:
- self.paginator.object_list[self.paginator.per_page]
- except IndexError:
- return False
- return True
-
- def start_index(self):
- """
- Returns the 1-based index of the first object on this page,
- relative to total objects in the paginator.
- """
- ## TODO should this holler if you haven't defined the offset?
- return self.paginator.offset
+++ /dev/null
-# Copyright (c) 2008, Eric Florenzano
-# Copyright (c) 2010, 2011 Linaro Limited
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of the author nor the names of other
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-from django.conf import settings
-
-
-DEFAULT_PAGINATION = getattr(
- settings, 'PAGINATION_DEFAULT_PAGINATION', 20)
-DEFAULT_WINDOW = getattr(
- settings, 'PAGINATION_DEFAULT_WINDOW', 4)
-DEFAULT_MARGIN = getattr(
- settings, 'PAGINATION_DEFAULT_MARGIN', DEFAULT_WINDOW)
-DEFAULT_ORPHANS = getattr(
- settings, 'PAGINATION_DEFAULT_ORPHANS', 0)
-INVALID_PAGE_RAISES_404 = getattr(
- settings, 'PAGINATION_INVALID_PAGE_RAISES_404', False)
-DISPLAY_PAGE_LINKS = getattr(
- settings, 'PAGINATION_DISPLAY_PAGE_LINKS', True)
-PREVIOUS_LINK_DECORATOR = getattr(
- settings, 'PAGINATION_PREVIOUS_LINK_DECORATOR', "‹‹ ")
-NEXT_LINK_DECORATOR = getattr(
- settings, 'PAGINATION_NEXT_LINK_DECORATOR', " ››")
-DISPLAY_DISABLED_PREVIOUS_LINK = getattr(
- settings, 'PAGINATION_DISPLAY_DISABLED_PREVIOUS_LINK', False)
-DISPLAY_DISABLED_NEXT_LINK = getattr(
- settings, 'PAGINATION_DISPLAY_DISABLED_NEXT_LINK', False)
-DISABLE_LINK_FOR_FIRST_PAGE = getattr(
- settings, 'PAGINATION_DISABLE_LINK_FOR_FIRST_PAGE', True)
+++ /dev/null
-{% if is_paginated %}
-{% load i18n %}
-<div class="pagination">
- {% block previouslink %}
- {% if page_obj.has_previous %}
- {% if disable_link_for_first_page and page_obj.previous_page_number == 1 %}
- <a href="{{ request.path }}{% if getvars %}?{{ getvars|slice:"1:" }}{% endif %}" class="prev">{{ previous_link_decorator|safe }}{% trans "previous" %}</a>
- {% else %}
- <a href="?page{{ page_suffix }}={{ page_obj.previous_page_number }}{{ getvars }}" class="prev">{{ previous_link_decorator|safe }}{% trans "previous" %}</a>
- {% endif %}
- {% else %}
- {% if display_disabled_previous_link %}
- <span class="disabled prev">{{ previous_link_decorator|safe }}{% trans "previous" %}</span>
- {% endif %}
- {% endif %}
- {% endblock previouslink %}
- {% block pagelinks %}
- {% if display_page_links %}
- {% for page in pages %}
- {% if page %}
- {% ifequal page page_obj.number %}
- <span class="current page">{{ page }}</span>
- {% else %}
- {% if disable_link_for_first_page and page == 1 %}
- <a href="{{ request.path }}{% if getvars %}?{{ getvars|slice:"1:" }}{% endif %}" class="page">{{ page }}</a>
- {% else %}
- <a href="?page{{ page_suffix }}={{ page }}{{ getvars }}" class="page">{{ page }}</a>
- {% endif %}
- {% endifequal %}
- {% else %}
- ...
- {% endif %}
- {% endfor %}
- {% endif %}
- {% endblock pagelinks %}
- {% block nextlink %}
- {% if page_obj.has_next %}
- <a href="?page{{ page_suffix }}={{ page_obj.next_page_number }}{{ getvars }}" class="next">{% trans "next" %}{{ next_link_decorator|safe }}</a>
- {% else %}
- {% if display_disabled_next_link %}
- <span class="disabled next">{% trans "next" %}{{ next_link_decorator|safe }}</span>
- {% endif %}
- {% endif %}
- {% endblock nextlink %}
-</div>
-{% endif %}
+++ /dev/null
-# Copyright (c) 2008, Eric Florenzano
-# Copyright (c) 2010, 2011 Linaro Limited
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of the author nor the names of other
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-from django.conf import settings
-from django.core.exceptions import ImproperlyConfigured
-from django.core.paginator import Paginator, InvalidPage
-from django.http import Http404
-from django.template import (
- Context,
- Library,
- Node,
- TemplateSyntaxError,
- Variable,
- loader,
-)
-
-try:
- from django.template.base import TOKEN_BLOCK
-except ImportError: # Django < 1.8
- from django.template import TOKEN_BLOCK
-
-from django.template.loader import select_template
-from django.utils.text import unescape_string_literal
-
-# TODO, import this normally later on
-from linaro_django_pagination.settings import *
-
-
-def do_autopaginate(parser, token):
- """
- Splits the arguments to the autopaginate tag and formats them correctly.
-
- Syntax is:
-
- autopaginate QUERYSET [PAGINATE_BY] [ORPHANS] [as NAME]
- """
- # Check whether there are any other autopaginations are later in this template
- expr = lambda obj: (obj.token_type == TOKEN_BLOCK and \
- len(obj.split_contents()) > 0 and obj.split_contents()[0] == "autopaginate")
- multiple_paginations = len([tok for tok in parser.tokens if expr(tok)]) > 0
-
- i = iter(token.split_contents())
- paginate_by = None
- queryset_var = None
- context_var = None
- orphans = None
- word = None
- try:
- word = next(i)
- assert word == "autopaginate"
- queryset_var = next(i)
- word = next(i)
- if word != "as":
- paginate_by = word
- try:
- paginate_by = int(paginate_by)
- except ValueError:
- pass
- word = next(i)
- if word != "as":
- orphans = word
- try:
- orphans = int(orphans)
- except ValueError:
- pass
- word = next(i)
- assert word == "as"
- context_var = next(i)
- except StopIteration:
- pass
- if queryset_var is None:
- raise TemplateSyntaxError(
- "Invalid syntax. Proper usage of this tag is: "
- "{% autopaginate QUERYSET [PAGINATE_BY] [ORPHANS]"
- " [as CONTEXT_VAR_NAME] %}")
- return AutoPaginateNode(queryset_var, multiple_paginations, paginate_by, orphans, context_var)
-
-
-class AutoPaginateNode(Node):
- """
- Emits the required objects to allow for Digg-style pagination.
-
- First, it looks in the current context for the variable specified, and using
- that object, it emits a simple ``Paginator`` and the current page object
- into the context names ``paginator`` and ``page_obj``, respectively.
-
- It will then replace the variable specified with only the objects for the
- current page.
-
- .. note::
-
- It is recommended to use *{% paginate %}* after using the autopaginate
- tag. If you choose not to use *{% paginate %}*, make sure to display the
- list of available pages, or else the application may seem to be buggy.
- """
- def __init__(self, queryset_var, multiple_paginations, paginate_by=None,
- orphans=None, context_var=None):
- if paginate_by is None:
- paginate_by = DEFAULT_PAGINATION
- if orphans is None:
- orphans = DEFAULT_ORPHANS
- self.queryset_var = Variable(queryset_var)
- if isinstance(paginate_by, int):
- self.paginate_by = paginate_by
- else:
- self.paginate_by = Variable(paginate_by)
- if isinstance(orphans, int):
- self.orphans = orphans
- else:
- self.orphans = Variable(orphans)
- self.context_var = context_var
- self.multiple_paginations = multiple_paginations
-
- def render(self, context):
- # Save multiple_paginations state in context
- if self.multiple_paginations and 'multiple_paginations' not in context:
- context['multiple_paginations'] = True
-
- if context.get('multiple_paginations') or getattr(context, "paginator", None):
- page_suffix = '_%s' % self.queryset_var
- else:
- page_suffix = ''
-
- key = self.queryset_var.var
- value = self.queryset_var.resolve(context)
- if isinstance(self.paginate_by, int):
- paginate_by = self.paginate_by
- else:
- paginate_by = self.paginate_by.resolve(context)
- if isinstance(self.orphans, int):
- orphans = self.orphans
- else:
- orphans = self.orphans.resolve(context)
- paginator = Paginator(value, paginate_by, orphans)
- try:
- request = context['request']
- except KeyError:
- raise ImproperlyConfigured(
- "You need to enable 'django.core.context_processors.request'."
- " See linaro-django-pagination/README file for TEMPLATE_CONTEXT_PROCESSORS details")
- try:
- page_obj = paginator.page(request.page(page_suffix))
- except InvalidPage:
- if INVALID_PAGE_RAISES_404:
- raise Http404('Invalid page requested. If DEBUG were set to ' +
- 'False, an HTTP 404 page would have been shown instead.')
- context[key] = []
- context['invalid_page'] = True
- return ''
- if self.context_var is not None:
- context[self.context_var] = page_obj.object_list
- else:
- context[key] = page_obj.object_list
- context['paginator'] = paginator
- context['page_obj'] = page_obj
- context['page_suffix'] = page_suffix
- return ''
-
-
-class PaginateNode(Node):
-
- def __init__(self, template=None):
- self.template = template
-
- def render(self, context):
- template_list = ['pagination/pagination.html']
- new_context = paginate(context)
- if self.template:
- template_list.insert(0, self.template)
- return loader.render_to_string(template_list, new_context,
- context_instance = context)
-
-
-
-def do_paginate(parser, token):
- """
- Emits the pagination control for the most recent autopaginate list
-
- Syntax is:
-
- paginate [using "TEMPLATE"]
-
- Where TEMPLATE is a quoted template name. If missing the default template
- is used (paginate/pagination.html).
- """
- argv = token.split_contents()
- argc = len(argv)
- if argc == 1:
- template = None
- elif argc == 3 and argv[1] == 'using':
- template = unescape_string_literal(argv[2])
- else:
- raise TemplateSyntaxError(
- "Invalid syntax. Proper usage of this tag is: "
- "{% paginate [using \"TEMPLATE\"] %}")
- return PaginateNode(template)
-
-
-def paginate(context, window=DEFAULT_WINDOW, margin=DEFAULT_MARGIN):
- """
- Renders the ``pagination/pagination.html`` template, resulting in a
- Digg-like display of the available pages, given the current page. If there
- are too many pages to be displayed before and after the current page, then
- elipses will be used to indicate the undisplayed gap between page numbers.
-
- Requires one argument, ``context``, which should be a dictionary-like data
- structure and must contain the following keys:
-
- ``paginator``
- A ``Paginator`` or ``QuerySetPaginator`` object.
-
- ``page_obj``
- This should be the result of calling the page method on the
- aforementioned ``Paginator`` or ``QuerySetPaginator`` object, given
- the current page.
-
- This same ``context`` dictionary-like data structure may also include:
-
- ``getvars``
- A dictionary of all of the **GET** parameters in the current request.
- This is useful to maintain certain types of state, even when requesting
- a different page.
-
- Argument ``window`` is number to pages before/after current page. If window
- exceeds pagination border (1 and end), window is moved to left or right.
-
- Argument ``margin``` is number of pages on start/end of pagination.
- Example:
- window=2, margin=1, current=6 1 ... 4 5 [6] 7 8 ... 11
- window=2, margin=0, current=1 [1] 2 3 4 5 ...
- window=2, margin=0, current=5 ... 3 4 [5] 6 7 ...
- window=2, margin=0, current=11 ... 7 8 9 10 [11]
- """
-
- if window < 0:
- raise ValueError('Parameter "window" cannot be less than zero')
- if margin < 0:
- raise ValueError('Parameter "margin" cannot be less than zero')
- try:
- paginator = context['paginator']
- page_obj = context['page_obj']
- page_suffix = context.get('page_suffix', '')
- page_range = list(paginator.page_range)
- # Calculate the record range in the current page for display.
- records = {'first': 1 + (page_obj.number - 1) * paginator.per_page}
- records['last'] = records['first'] + paginator.per_page - 1
- if records['last'] + paginator.orphans >= paginator.count:
- records['last'] = paginator.count
-
- # figure window
- window_start = page_obj.number - window - 1
- window_end = page_obj.number + window
-
- # solve if window exceeded page range
- if window_start < 0:
- window_end = window_end - window_start
- window_start = 0
- if window_end > paginator.num_pages:
- window_start = max(0, window_start - (window_end - paginator.num_pages))
- window_end = paginator.num_pages
- pages = page_range[window_start:window_end]
-
- # figure margin and add elipses
- if margin > 0:
- # figure margin
- tmp_pages = set(pages)
- tmp_pages = tmp_pages.union(page_range[:margin])
- tmp_pages = tmp_pages.union(page_range[-margin:])
- tmp_pages = list(tmp_pages)
- tmp_pages.sort()
- pages = []
- pages.append(tmp_pages[0])
- for i in range(1, len(tmp_pages)):
- # figure gap size => add elipses or fill in gap
- gap = tmp_pages[i] - tmp_pages[i - 1]
- if gap >= 3:
- pages.append(None)
- elif gap == 2:
- pages.append(tmp_pages[i] - 1)
- pages.append(tmp_pages[i])
- else:
- if pages[0] != 1:
- pages.insert(0, None)
- if pages[-1] != paginator.num_pages:
- pages.append(None)
-
- new_context = {
- 'MEDIA_URL': settings.MEDIA_URL,
- 'STATIC_URL': getattr(settings, "STATIC_URL", None),
- 'disable_link_for_first_page': DISABLE_LINK_FOR_FIRST_PAGE,
- 'display_disabled_next_link': DISPLAY_DISABLED_NEXT_LINK,
- 'display_disabled_previous_link': DISPLAY_DISABLED_PREVIOUS_LINK,
- 'display_page_links': DISPLAY_PAGE_LINKS,
- 'is_paginated': paginator.count > paginator.per_page,
- 'next_link_decorator': NEXT_LINK_DECORATOR,
- 'page_obj': page_obj,
- 'page_suffix': page_suffix,
- 'pages': pages,
- 'paginator': paginator,
- 'previous_link_decorator': PREVIOUS_LINK_DECORATOR,
- 'records': records,
- }
- if 'request' in context:
- getvars = context['request'].GET.copy()
- if 'page%s' % page_suffix in getvars:
- del getvars['page%s' % page_suffix]
- if len(getvars.keys()) > 0:
- new_context['getvars'] = "&%s" % getvars.urlencode()
- else:
- new_context['getvars'] = ''
- return new_context
- except (KeyError, AttributeError):
- return {}
-
-
-register = Library()
-register.tag('paginate', do_paginate)
-register.tag('autopaginate', do_autopaginate)
+++ /dev/null
-{% extends "django_testproject/base.html" %}
-{% load pagination_tags %}
-
-
-{% block content %}
-<p>This page demonstrates how autopaginate behaves under certain conditions</p>
-<p>Below you can see a list of {{ item_list|length }} items.</p>
-{% autopaginate item_list %}
-{% for item in item_list %}
-<p>Item {{item}}</p>
-{% endfor %}
-{% paginate %}
-{% endblock %}
+++ /dev/null
-{% extends "django_testproject/base.html" %}
-{% load pagination_tags %}
-
-
-{% block content %}
-<p>This page demonstrates how autopaginate behaves under certain conditions</p>
-<p>Below you can see two lists.</p>
-<p>First list has {{ first_item_list|length }} items.</p>
-{% autopaginate first_item_list 5 %}
-{% for item in first_item_list %}
-<p>{{item}}</p>
-{% endfor %}
-{% paginate using "pagination/custom_pagination.html" %}
-
-<p>Second list has {{ second_item_list|length}} items.</p>
-{% autopaginate second_item_list 5 %}
-{% paginate %}
-{% for item in second_item_list %}
-<p>{{item}}</p>
-{% endfor %}
-{% endblock %}
+++ /dev/null
-{% extends "pagination/pagination.html" %}
-
-
-{% block previouslink %}
- <p style="color: red; background-color: white;">This part is custom</p>
- {{ block.super }}
-{% endblock previouslink %}
+++ /dev/null
-# Copyright (c) 2010, 2011 Linaro Limited
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of the author nor the names of other
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-from django.conf.urls.defaults import (
- patterns, url, include, handler500, handler404)
-
-urlpatterns = patterns(
- 'example.views',
- url(r'^list/$', 'list'),
- url(r'^complex-list/$', 'complex_list'))
+++ /dev/null
-# Copyright (c) 2010, 2011 Linaro Limited
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of the author nor the names of other
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-from django.shortcuts import render_to_response
-from django.template import RequestContext
-
-
-def list(request):
- return render_to_response("example/list.html", {
- 'item_list': range(1000),
- }, RequestContext(request))
-
-
-def complex_list(request):
- return render_to_response("example/two_lists.html", {
- 'first_item_list': ["first list item %d" % item for item in range(1000)],
- 'second_item_list': ["second list item %d" % item for item in range(1000)],
- }, RequestContext(request))
+++ /dev/null
-#!/usr/bin/env python
-# Copyright (c) 2010, 2011 Linaro Limited
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of the author nor the names of other
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-import logging
-
-from django.core.management import execute_manager
-
-try:
- from linaro_django_pagination.test_project import settings
-except ImportError as ex:
- logging.exception("Unable to import application settings")
- raise SystemExit(ex)
-
-
-if __name__ == "__main__":
- execute_manager(settings)
+++ /dev/null
-# Copyright (c) 2010, 2011 Linaro Limited
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of the author nor the names of other
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import sys
-import os
-
-# Add this directory to path so that 'example' can be imported later
-# below. Without this the runner will fail when started via ``setup.py
-# test``
-sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
-
-from django_testproject.settings import gen_settings
-
-
-locals().update(
- gen_settings(
- INSTALLED_APPS=[
- 'example',
- 'linaro_django_pagination'],
- MIDDLEWARE_CLASSES=[
- 'linaro_django_pagination.middleware.PaginationMiddleware'],
- TEMPLATE_CONTEXT_PROCESSORS=[
- # Request processor needs to be enabled
- 'django.core.context_processors.request'],
- ROOT_URLCONF="linaro_django_pagination.test_project.urls"),
- TEMPLATE_LOADERS = ['django.template.loaders.app_directories.Loader'],
- SECRET_KEY = 'not for production',
- )
+++ /dev/null
-# Copyright (c) 2010, 2011 Linaro Limited
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of the author nor the names of other
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-def run_tests():
- from django_testproject.tests import run_tests_for
- run_tests_for("linaro_django_pagination.test_project.settings")
-
-
-if __name__ == '__main__':
- run_tests()
+++ /dev/null
-# Copyright (c) 2010, 2011 Linaro Limited
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of the author nor the names of other
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-from django.conf.urls.defaults import (
- patterns, url, include, handler500, handler404)
-
-# Empty patterns so that test project can be started and would work normally
-urlpatterns = patterns('', url('', include('example.urls')))
+++ /dev/null
-from .test_main import *
+++ /dev/null
-#!/usr/bin/env python
-
-import django
-import os
-import sys
-
-from django.core.management import call_command
-
-
-def runtests():
- os.environ['DJANGO_SETTINGS_MODULE'] = 'linaro_django_pagination.tests.settings'
-
- try:
- django.setup()
- except AttributeError: # for Django 1.6 compatible
- pass
-
- failures = call_command('test', 'linaro_django_pagination')
- sys.exit(bool(failures))
-
-if __name__ == '__main__':
- runtests()
+++ /dev/null
-DATABASES = {
- 'default': {
- 'NAME': ':memory:',
- 'ENGINE': 'django.db.backends.sqlite3',
- }
-}
-
-SECRET_KEY = 'fake-key'
-
-INSTALLED_APPS = (
- 'linaro_django_pagination',
-)
+++ /dev/null
-# Copyright (c) 2008, Eric Florenzano
-# Copyright (c) 2010, 2011 Linaro Limited
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of the author nor the names of other
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-from django.core.paginator import Paginator
-from django.http import HttpRequest as DjangoHttpRequest
-from django.template import Template, Context
-
-try:
- from django.test import SimpleTestCase
-except ImportError: # Django 1.2 compatible
- from django.test import TestCase as SimpleTestCase
-
-from linaro_django_pagination.paginator import InfinitePaginator, FinitePaginator
-from linaro_django_pagination.templatetags.pagination_tags import paginate
-from linaro_django_pagination.middleware import PaginationMiddleware
-
-
-class HttpRequest(DjangoHttpRequest):
- page = lambda self, suffix: 1
-
-
-class CommonTestCase(SimpleTestCase):
- def test_records_for_the_first_page(self):
- p = Paginator(range(15), 2)
- pg = paginate({'paginator': p, 'page_obj': p.page(1)})
- self.assertListEqual(pg['pages'], [1, 2, 3, 4, 5, 6, 7, 8])
- self.assertEqual(pg['records']['first'], 1)
- self.assertEqual(pg['records']['last'], 2)
-
- def test_records_for_the_last_page(self):
- p = Paginator(range(15), 2)
- pg = paginate({'paginator': p, 'page_obj': p.page(8)})
- self.assertListEqual(pg['pages'], [1, 2, 3, 4, 5, 6, 7, 8])
- self.assertEqual(pg['records']['first'], 15)
- self.assertEqual(pg['records']['last'], 15)
-
- def test_pages_list(self):
- p = Paginator(range(17), 2)
- self.assertEqual(paginate({'paginator': p, 'page_obj': p.page(1)})['pages'], [1, 2, 3, 4, 5, 6, 7, 8, 9])
-
- def test_page_with_empty_objects_list(self):
- p = Paginator(range(0), 2)
- self.assertListEqual(paginate({'paginator': p, 'page_obj': p.page(1)})['pages'], [1])
-
-
-class DefaultWindowTestCase(SimpleTestCase):
- """
- Test paginate using default window setting
- moving the window from 1 ... to end
- window size = 2, margin = 2
- window = 2 -> show 5 pages
- """
- def setUp(self):
- self.p = Paginator(range(31), 2)
-
- def test_on_start_page_1(self):
- # [1] 2 3 4 5 ... 15, 16
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(1)}, 2, 2)['pages'],
- [1, 2, 3, 4, 5, None, 15, 16]
- )
-
- def test_on_start_page_2(self):
- # 1 [2] 3 4 5 ... 15, 16
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(2)}, 2, 2)['pages'],
- [1, 2, 3, 4, 5, None, 15, 16]
- )
-
- def test_on_start_page_3(self):
- # 1 2 [3] 4 5 ... 15, 16
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(3)}, 2, 2)['pages'],
- [1, 2, 3, 4, 5, None, 15, 16]
- )
-
- def test_on_start_page_4(self):
- # 1 2 3 [4] 5 6 ... 15, 16
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(4)}, 2, 2)['pages'],
- [1, 2, 3, 4, 5, 6, None, 15, 16])
-
- def test_on_start_page_5(self):
- # 1 2 3 4 [5] 6 7 ... 15, 16
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(5)}, 2, 2)['pages'],
- [1, 2, 3, 4, 5, 6, 7, None, 15, 16]
- )
-
- def test_in_middle(self):
- # 1 2 ... 5 6 [7] 8 9 ... 15, 16
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(7)}, 2, 2)['pages'],
- [1, 2, None, 5, 6, 7, 8, 9, None, 15, 16]
- )
-
- def test_on_end_page_13(self):
- # 1 2 ... 12 [13] 14 15 16
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(13)}, 2, 2)['pages'],
- [1, 2, None, 11, 12, 13, 14, 15, 16],
- )
-
- def test_on_end(self):
- # 1 2 ... 12 13 14 15 [16
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(16)}, 2, 2)['pages'],
- [1, 2, None, 12, 13, 14, 15, 16]
- )
-
-
-class NoMarginTestCase(SimpleTestCase):
- def setUp(self):
- self.p = Paginator(range(31), 2)
-
- def test_on_start(self):
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(3)}, 2, 0)['pages'],
- [1, 2, 3, 4, 5, None],
- )
-
- def test_in_middle(self):
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(5)}, 2, 0)['pages'],
- [None, 3, 4, 5, 6, 7, None],
- )
-
- def test_on_end(self):
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(16)}, 2, 0)['pages'],
- [None, 12, 13, 14, 15, 16],
- )
-
-
-class ZeroWindowZeroMarginTestCase(SimpleTestCase):
- """
- Test paginate using window=0 and margin=0
- """
- def setUp(self):
- self.p = Paginator(range(31), 2)
-
- def test_on_start_page_1(self):
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(1)}, 0, 0)['pages'],
- [1, None],
- )
-
- def test_in_middle_page_2(self):
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(2)}, 0, 0)['pages'],
- [None, 2, None],
- )
-
- def test_in_middle_page_3(self):
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(3)}, 0, 0)['pages'],
- [None, 3, None],
- )
-
- def test_in_middle_page_10(self):
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(10)}, 0, 0)['pages'],
- [None, 10, None],
- )
-
- def test_in_middle_page_14(self):
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(14)}, 0, 0)['pages'],
- [None, 14, None],
- )
-
- def test_in_middle_page_15(self):
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(15)}, 0, 0)['pages'],
- [None, 15, None],
- )
-
- def test_on_end_page_16(self):
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(16)}, 0, 0)['pages'],
- [None, 16],
- )
-
-
-class NoEllipsisTestCase(SimpleTestCase):
- """
- Tests a case where should be no any ellipsis pages.
- """
- def setUp(self):
- self.p = Paginator(range(100), 25)
-
- def test_on_start(self):
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(1)}, 2, 0)['pages'],
- [1, 2, 3, 4],
- )
-
- def test_in_middle_page_2(self):
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(2)}, 2, 0)['pages'],
- [1, 2, 3, 4],
- )
-
- def test_in_middle_page_3(self):
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(3)}, 2, 0)['pages'],
- [1, 2, 3, 4],
- )
-
- def test_on_end(self):
- self.assertListEqual(
- paginate({'paginator': self.p, 'page_obj': self.p.page(4)}, 2, 0)['pages'],
- [1, 2, 3, 4],
- )
-
-
-class SpecialTestCase(SimpleTestCase):
- def test_middle_with_no_window_and_margin_1(self):
- p = Paginator(range(31), 2)
- self.assertListEqual(
- paginate({'paginator': p, 'page_obj': p.page(5)}, 0, 1)['pages'],
- [1, None, 5, None, 16],
- )
-
- def test_middle_with_no_window_and_margin_4(self):
- p = Paginator(range(21), 2, 1)
- self.assertListEqual(
- paginate({'paginator': p, 'page_obj': p.page(1)}, 0, 4)['pages'],
- [1, 2, 3, 4, None, 7, 8, 9, 10],
- )
-
-
-class TemplateRenderingTestCase(SimpleTestCase):
- def test_default_tag_options(self):
- t = Template("{% load pagination_tags %}{% autopaginate var %}{% paginate %}")
- self.assertIn(
- '<div class="pagination">',
- t.render(Context({'var': range(21), 'request': HttpRequest()})),
- )
-
- def test_paginate_by_option(self):
- t = Template("{% load pagination_tags %}{% autopaginate var 20 %}{% paginate %}")
- self.assertIn(
- '<div class="pagination">',
- t.render(Context({'var': range(21), 'request': HttpRequest()})),
- )
-
- def test_orphans_option(self):
- t = Template("{% load pagination_tags %}{% autopaginate var by %}{% paginate %}")
- content = t.render(Context({'var': range(21), 'by': 20, 'request': HttpRequest()}))
- self.assertIn('<div class="pagination">', content)
- self.assertIn('<a href="?page=2"', content)
-
- def test_as_option(self):
- t = Template("{% load pagination_tags %}{% autopaginate var by as foo %}{{ foo }}")
- self.assertEqual(
- t.render(Context({'var': range(21), 'by': 20, 'request': HttpRequest()})),
- str(range(20)),
- )
-
- def test_multiple_pagination(self):
- t = Template("{% load pagination_tags %}{% autopaginate var2 by as foo2 %}{% paginate %}"
- "{% autopaginate var by as foo %}{% paginate %}")
- content = t.render(Context({'var': range(21), 'var2': range(50, 121), 'by': 20, 'request': HttpRequest()}))
- self.assertIn('<div class="pagination">', content)
- self.assertIn('<a href="?page_var2=2"', content)
- self.assertIn('<a href="?page_var=2"', content)
-
-
-class InfinitePaginatorTestCase(SimpleTestCase):
- def setUp(self):
- self.p = InfinitePaginator(range(20), 2, link_template='/bacon/page/%d')
-
- def test_paginator_repr(self):
- self.assertEqual(
- repr(InfinitePaginator),
- "<class 'linaro_django_pagination.paginator.InfinitePaginator'>",
- )
-
- def test_validate_number(self):
- self.assertEqual(self.p.validate_number(2), 2)
-
- def test_orphans(self):
- self.assertEqual(self.p.orphans, 0)
-
- def test_page_repr(self):
- self.assertEqual(repr(self.p.page(3)), '<Page 3>')
-
- def test_page_end_index(self):
- self.assertEqual(self.p.page(3).end_index(), 6)
-
- def test_page_has_next(self):
- self.assertTrue(self.p.page(3).has_next(), True)
-
- def test_page_has_previous(self):
- self.assertTrue(self.p.page(3).has_previous(), True)
-
- def test_page_next_link(self):
- self.assertEqual(self.p.page(3).next_link(), '/bacon/page/4')
-
- def test_page_previous_link(self):
- self.assertEqual(self.p.page(3).previous_link(), '/bacon/page/2')
-
- def test_last_page_which_has_no_next_page(self):
- self.assertFalse(self.p.page(10).has_next())
-
- def test_first_page_which_has_no_previous_page(self):
- self.assertFalse(self.p.page(1).has_previous())
-
-
-class FinitePaginatorTestCase(SimpleTestCase):
- def setUp(self):
- self.p = FinitePaginator(range(20), 2, offset=10, link_template='/bacon/page/%d')
-
- def test_repr(self):
- self.assertEqual(
- repr(FinitePaginator),
- "<class 'linaro_django_pagination.paginator.FinitePaginator'>"
- )
-
- def test_validate_number(self):
- self.assertEqual(self.p.validate_number(2), 2)
-
- def test_orphans(self):
- self.assertEqual(self.p.orphans, 0)
-
- def test_page_repr(self):
- self.assertEqual(repr(self.p.page(3)), '<Page 3>')
-
- def test_page_start_index(self):
- self.assertEqual(self.p.page(3).start_index(), 10)
-
- def test_page_end(self):
- self.assertEqual(self.p.page(3).end_index(), 6)
-
- def test_page_has_next(self):
- self.assertTrue(self.p.page(3).has_next(), True)
-
- def test_page_has_previous(self):
- self.assertTrue(self.p.page(3).has_previous(), True)
-
- def test_page_next_link(self):
- self.assertEqual(self.p.page(3).next_link(), '/bacon/page/4')
-
- def test_page_previous_link(self):
- self.assertEqual(self.p.page(3).previous_link(), '/bacon/page/2')
-
- def test_on_start_page_repr(self):
- self.assertEqual(repr(self.p.page(2)), '<Page 2>')
-
- def test_on_start_has_no_next(self):
- self.assertTrue(self.p.page(2).has_next(), False)
-
- def test_on_start_has_previous(self):
- self.assertTrue(self.p.page(2).has_previous(), True)
-
- def test_on_start_has_next_link(self):
- self.assertEqual(self.p.page(2).next_link(), '/bacon/page/3')
-
- def test_on_start_has_previous_link(self):
- self.assertEqual(self.p.page(2).previous_link(), '/bacon/page/1')
-
-
-class MiddlewareTestCase(SimpleTestCase):
- """
- Test middleware
- """
- def test_get_page_in_request(self):
- middleware = PaginationMiddleware()
- request = DjangoHttpRequest()
- middleware.process_request(request)
- self.assertEqual(request.page(''), 1)
import os
from setuptools import setup, find_packages
-os.environ['DJANGO_SETTINGS_MODULE'] = 'linaro_django_pagination.tests.settings'
+os.environ['DJANGO_SETTINGS_MODULE'] = 'fnp_django_pagination.tests.settings'
setup(
- name='linaro-django-pagination',
+ name='fnp-django-pagination',
# Magic version handling with versiontools
- version=":versiontools:linaro_django_pagination:__version__",
+ version=":versiontools:fnp_django_pagination:__version__",
author='Zygmunt Krynicki',
author_email='zygmunt.krynicki@linaro.org',
- description="linaro-django-pagination",
+ description="fnp-django-pagination",
long_description=open("README.rst").read(),
keywords='pagination,django',
- url='https://github.com/zyga/django-pagination',
- test_suite="linaro_django_pagination.tests.runner.runtests",
+ url='https://github.com/fnp/django-pagination',
+ test_suite="fnp_django_pagination.tests.runner.runtests",
license='BSD',
packages=find_packages(),
classifiers=[