Skip to content

Instantly share code, notes, and snippets.

@rhblind
Last active December 13, 2015 23:59
Show Gist options
  • Save rhblind/4995490 to your computer and use it in GitHub Desktop.
Save rhblind/4995490 to your computer and use it in GitHub Desktop.
Django pagination template tag.
# -*- coding: utf-8 -*-
from django import template
from django.utils.encoding import smart_unicode
register = template.Library()
class PaginateNode(template.Node):
"""
Pagination template node.
"""
@classmethod
def handle_token(cls, parser, token):
"""
Class method for parsing token and returning a Node
"""
tokens = token.contents.split()
if len(tokens) == 3:
if not (tokens[1].isalpha() and tokens[1] in "previous next"):
raise template.TemplateSyntaxError("Valid arguments to %r is 'previous' or 'next'" % tokens[0])
return cls(direction=tokens[1], page_expr=parser.compile_filter(tokens[2]))
else:
raise template.TemplateSyntaxError("%r tag requires exactly two argument" % tokens[0])
def __init__(self, direction=None, page_expr=None):
if direction is None:
raise template.TemplateSyntaxError("PaginateNode requires a paginate direction")
if page_expr is None:
raise template.TemplateSyntaxError("PaginateNode requires a Page() instance context variable")
self.direction = direction
self.page_expr = page_expr
def render(self, context):
"""
Build and returns the querystring.
"""
return smart_unicode("&".join((self.get_page_string(context),
self.get_get_string(context))))
def get_page_string(self, context):
"""
Returns the page string part
of the querystring.
"""
page = self.page_expr.resolve(context)
if self.direction == u"next" and page.has_next():
next_page = page.next_page_number()
elif self.direction == u"previous" and page.has_previous():
next_page = page.previous_page_number()
else:
next_page = page.number
return smart_unicode("?page=%(page)s" % {"page": next_page})
def get_get_string(self, context):
"""
Returns the GET string part of
the querystring.
"""
get_data = context["request"].GET
def build_str(query_dict):
"""
Yields querystring items for
GET data
"""
page = self.page_expr.var
q_dict = query_dict.copy()
for key, value in q_dict.iterlists():
# Make sure we don't get the page context
# variable here
if key == page.var:
continue
if len(value) > 1:
for item in value:
yield "%(key)s=%(value)s" % {"key": key, "value": item}
elif len(value):
item = value.pop()
yield "%(key)s=%(value)s" % {"key": key, "value": item}
else:
continue
return smart_unicode("&".join(build_str(get_data)))
@register.tag
def paginate(parser, token):
"""
Returns a querystring suitable to pass in a GET request for
obtaining the next page in a paginator. Must be passed
a Page() context variable.
Example::
<a href="{% paginate previous page %}">Previous page</a>
or
<a href="{% paginate next page %}">Next page</a>
"""
return PaginateNode.handle_token(parser, token)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment