Created
November 12, 2010 10:25
-
-
Save dchaplinsky/673954 to your computer and use it in GitHub Desktop.
Port of django_pagination package to make it works with jinja2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% macro render_pagination(pages) -%} | |
{% if pages.is_paginated %} | |
<div class="pagination"> | |
{% if pages.page_obj.has_previous() %} | |
<a href="?page={{ pages.page_obj.previous_page_number() }}{{ pages.getvars }}{{ pages.hashtag }}" class="prev">‹‹ previous</a> | |
{% else %} | |
<span class="disabled prev">‹‹ previous</span> | |
{% endif %} | |
{% for page in pages.pages %} | |
{% if page %} | |
{% if page == pages.page_obj.number %} | |
<span class="current page">{{ page }}</span> | |
{% else %} | |
<a href="?page={{ page }}{{ pages.getvars }}{{ pages.hashtag }}" class="page">{{ page }}</a> | |
{% endif %} | |
{% else %} | |
... | |
{% endif %} | |
{% endfor %} | |
{% if pages.page_obj.has_next() %} | |
<a href="?page={{ pages.page_obj.next_page_number() }}{{ pages.getvars }}{{ pages.hashtag }}" class="next">next ››</a> | |
{% else %} | |
<span class="disabled next">next ››</span> | |
{% endif %} | |
</div> | |
{% endif %} | |
{%- endmacro %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Code below is borrowed from the django_pagination module by James Tauber and Pinax Team, | |
# http://pinaxproject.com/docs/dev/external/pagination/index.html | |
def get_page(self): | |
""" | |
A function which will be monkeypatched onto the request to get the current | |
integer representing the current page. | |
""" | |
try: | |
return int(self.REQUEST['page']) | |
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 = property(get_page) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
try: | |
set | |
except NameError: | |
from sets import Set as set | |
from django.core.paginator import Paginator, InvalidPage | |
from django.http import Http404 | |
from coffin import template | |
from jinja2 import nodes | |
from jinja2.ext import Extension | |
from jinja2.exceptions import TemplateSyntaxError | |
from django.conf import settings | |
register = template.Library() | |
# Most of the code below is borrowed from the django_pagination module by James Tauber and Pinax Team, | |
# http://pinaxproject.com/docs/dev/external/pagination/index.html | |
DEFAULT_PAGINATION = getattr(settings, 'PAGINATION_DEFAULT_PAGINATION', 20) | |
DEFAULT_WINDOW = getattr(settings, 'PAGINATION_DEFAULT_WINDOW', 4) | |
DEFAULT_ORPHANS = getattr(settings, 'PAGINATION_DEFAULT_ORPHANS', 0) | |
INVALID_PAGE_RAISES_404 = getattr(settings, | |
'PAGINATION_INVALID_PAGE_RAISES_404', True) | |
class AutopaginateExtension(Extension): | |
""" | |
Applies pagination to the given dataset (and saves truncated dataset to the context variable), | |
sets context variable with data enough to build html for paginator | |
General syntax: | |
{% autopaginate dataset [as ctx_variable] %} | |
if "as" part is omitted, trying to save truncated dataset back to the original | |
context variable. | |
Pagination data is saved to the NAME_pages context variable, where NAME is | |
original name of the dataset or ctx_variable | |
""" | |
tags = set(['autopaginate']) | |
def parse(self, parser): | |
lineno = parser.stream.next().lineno | |
value = parser.parse_expression() | |
if parser.stream.skip_if('name:as'): | |
name = parser.stream.expect('name').value | |
elif hasattr(value, 'name'): | |
name = value.name | |
else: | |
raise TemplateSyntaxError("Cannot determine the name of objects you want to paginate, use 'as foobar' syntax", lineno) | |
while not parser.stream.current.type == 'block_end': | |
parser.stream.skip() | |
return [ | |
nodes.Assign(nodes.Name(name + '_pages', 'store'), | |
self.call_method('_render_pages', [value, nodes.Name('request', 'load')]) | |
).set_lineno(lineno), | |
nodes.Assign(nodes.Name(name, 'store'), | |
nodes.Getattr(nodes.Name(name + '_pages', 'load'), 'object_list', nodes.Impossible()) | |
).set_lineno(lineno), | |
] | |
def _render_pages(self, objs, request, window=DEFAULT_WINDOW, hashtag=''): | |
try: | |
paginator = Paginator(objs, DEFAULT_PAGINATION) | |
try: | |
page_obj = paginator.page(request.page) | |
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.') | |
page_range = 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 | |
# First and last are simply the first *n* pages and the last *n* pages, | |
# where *n* is the current window size. | |
first = set(page_range[:window]) | |
last = set(page_range[-window:]) | |
# Now we look around our current page, making sure that we don't wrap | |
# around. | |
current_start = page_obj.number-1-window | |
if current_start < 0: | |
current_start = 0 | |
current_end = page_obj.number-1+window | |
if current_end < 0: | |
current_end = 0 | |
current = set(page_range[current_start:current_end]) | |
pages = [] | |
# If there's no overlap between the first set of pages and the current | |
# set of pages, then there's a possible need for elusion. | |
if len(first.intersection(current)) == 0: | |
first_list = list(first) | |
first_list.sort() | |
second_list = list(current) | |
second_list.sort() | |
pages.extend(first_list) | |
diff = second_list[0] - first_list[-1] | |
# If there is a gap of two, between the last page of the first | |
# set and the first page of the current set, then we're missing a | |
# page. | |
if diff == 2: | |
pages.append(second_list[0] - 1) | |
# If the difference is just one, then there's nothing to be done, | |
# as the pages need no elusion and are correct. | |
elif diff == 1: | |
pass | |
# Otherwise, there's a bigger gap which needs to be signaled for | |
# elusion, by pushing a None value to the page list. | |
else: | |
pages.append(None) | |
pages.extend(second_list) | |
else: | |
unioned = list(first.union(current)) | |
unioned.sort() | |
pages.extend(unioned) | |
# If there's no overlap between the current set of pages and the last | |
# set of pages, then there's a possible need for elusion. | |
if len(current.intersection(last)) == 0: | |
second_list = list(last) | |
second_list.sort() | |
diff = second_list[0] - pages[-1] | |
# If there is a gap of two, between the last page of the current | |
# set and the first page of the last set, then we're missing a | |
# page. | |
if diff == 2: | |
pages.append(second_list[0] - 1) | |
# If the difference is just one, then there's nothing to be done, | |
# as the pages need no elusion and are correct. | |
elif diff == 1: | |
pass | |
# Otherwise, there's a bigger gap which needs to be signaled for | |
# elusion, by pushing a None value to the page list. | |
else: | |
pages.append(None) | |
pages.extend(second_list) | |
else: | |
differenced = list(last.difference(current)) | |
differenced.sort() | |
pages.extend(differenced) | |
to_return = { | |
'MEDIA_URL': settings.MEDIA_URL, | |
'pages': pages, | |
'records': records, | |
'page_obj': page_obj, | |
'object_list': page_obj.object_list, | |
'paginator': paginator, | |
'hashtag': hashtag, | |
'is_paginated': paginator.count > paginator.per_page, | |
} | |
getvars = request.GET.copy() | |
if 'page' in getvars: | |
del getvars['page'] | |
if len(getvars.keys()) > 0: | |
to_return['getvars'] = "&%s" % getvars.urlencode() | |
else: | |
to_return['getvars'] = '' | |
return to_return | |
except KeyError, AttributeError: | |
return {} | |
register.tag(AutopaginateExtension) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment