To enable "clean url" mode, install django-pagination, then just add to settings.py PAGINATION_CLEAN_URL = True and replace '.../pagination/templatetags/pagination_tags.py' with follow, and so add to 'pagination/templates/pagination/' folder pagination_clean_url.html file, with following code
Note: in urls.py should be like this:
url(r'^/foo/bar/\d*/?$', foobar_list_handle),
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | #pagination_tags.py
try:
set
except NameError:
from sets import Set as set
from django import template
from django.http import Http404
from django.core.paginator import Paginator, InvalidPage
from django.conf import settings
register = template.Library()
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', False)
CLEAN_URL = getattr(settings, 'PAGINATION_CLEAN_URL', False)
def do_autopaginate(parser, token):
"""
Splits the arguments to the autopaginate tag and formats them correctly.
"""
split = token.split_contents()
as_index = None
context_var = None
for i, bit in enumerate(split):
if bit == 'as':
as_index = i
break
if as_index is not None:
try:
context_var = split[as_index + 1]
except IndexError:
raise template.TemplateSyntaxError("Context variable assignment " +
"must take the form of {%% %r object.example_set.all ... as " +
"context_var_name %%}" % split[0])
del split[as_index:as_index + 2]
if len(split) == 2:
return AutoPaginateNode(split[1])
elif len(split) == 3:
return AutoPaginateNode(split[1], paginate_by=split[2],
context_var=context_var)
elif len(split) == 4:
try:
orphans = int(split[3])
except ValueError:
raise template.TemplateSyntaxError(u'Got %s, but expected integer.'
% split[3])
return AutoPaginateNode(split[1], paginate_by=split[2], orphans=orphans,
context_var=context_var)
else:
raise template.TemplateSyntaxError('%r tag takes one required ' +
'argument and one optional argument' % split[0])
class AutoPaginateNode(template.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, paginate_by=DEFAULT_PAGINATION,
orphans=DEFAULT_ORPHANS, context_var=None):
self.queryset_var = template.Variable(queryset_var)
if isinstance(paginate_by, int):
self.paginate_by = paginate_by
else:
self.paginate_by = template.Variable(paginate_by)
self.orphans = orphans
self.context_var = context_var
def render(self, context):
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)
paginator = Paginator(value, paginate_by, self.orphans)
try:
if CLEAN_URL:
try:
page = int(context['request'].path.split('/')[-2])
page_obj = paginator.page(page)
except ValueError:
page_obj = paginator.page(1)
else:
page_obj = paginator.page(context['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.')
context[key] = []
context['invalid_page'] = True
return u''
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
return u''
def paginate(context, window=DEFAULT_WINDOW, hashtag=''):
try:
paginator = context['paginator']
page_obj = context['page_obj']
if CLEAN_URL:
if page_obj.number == 1 and context['request'].path.split('/')[-2] != '1':
current_url = context['request'].path[1:-1]
else:
current_url = '/'.join(context['request'].path.split('/')[1:-2])
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,
'paginator': paginator,
'hashtag': hashtag,
'is_paginated': paginator.count > paginator.per_page,
}
if CLEAN_URL:
to_return['current_url'] = current_url
if 'request' in context:
getvars = context['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 {}
if CLEAN_URL:
template_path = 'pagination/pagination_clean_url.html'
else:
template_path = 'pagination/pagination.html'
register.inclusion_tag(template_path, takes_context=True)(
paginate)
register.tag('autopaginate', do_autopaginate)
#pagination_clean_url.html
{% if is_paginated %}
{% load i18n %}
<div class="pagination">
{% if page_obj.has_previous %}
<a href="/{{ current_url }}/{{ page_obj.previous_page_number }}/{{ getvars }}{{ hashtag }}" class="prev">‹‹ {% trans "previous" %}</a>
{% endif %}
{% for page in pages %}
{% if page %}
{% ifequal page page_obj.number %}
<span class="current page">{{ page }}</span>
{% else %}
<a href="/{{ current_url }}/{{ page }}/{{ getvars }}{{ hashtag }}" class="page">{{ page }}</a>
{% endifequal %}
{% else %}
...
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a href="/{{ current_url }}/{{ page_obj.next_page_number }}/{{ getvars }}{{ hashtag }}" class="next">{% trans "next" %} ››</a>
{% endif %}
</div>
{% endif %}
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 8 months ago
Comments
Please login first before commenting.