Super simple pagination, WITHOUT using Django's Paginator object
Once again, I've been struggling with pagination. It's not that I don't like Django's Paginator object ... it's that ... well, okay, I don't like it. Anyway, I just needed something painfully simple for this site, and Paginator seemed a little like overkill.
So here's my super-simple example - this is the code for the pagination that's on this very blog:
The view:
In the template:
And for what it's worth, although it's probably obvious, these are the corresponding patterns in my urls.py:
So here's my super-simple example - this is the code for the pagination that's on this very blog:
The view:
def list(request, category=None, username=None, date=None):
"""
List all entries, paginated
"""
template_name = 'list.html'
context = {}
per_page = 5
page = INT(request.GET.get('page', '1'))
if category:
context['category'] = category
grouped_list = entries_by_category(request, category)
elif username:
context['author'] = username
try:
user = User.objects.get(username=username)
grouped_list = Post.objects.filter(author=user.id).order_by('-created_at')
except ObjectDoesNotExist:
grouped_list = None
elif date:
context['date'] = date
grouped_list = Post.objects.filter(created_at__startswith=date, publish=True).order_by('-created_at')
else:
grouped_list = Post.objects.filter(publish=True).order_by('-created_at')
for entry in grouped_list:
entry.category_list = Category.objects.filter(postcategory__post__pk=entry.id)
entry.comments = Comment.objects.filter(post=entry.id)
total_entries = grouped_list.count()
total_pages = (total_entries/per_page)+1
context['page_range'] = range(1, total_pages+1)
offset = (page * per_page) - per_page
limit = offset + per_page
entry_list = grouped_list[offset:limit]
context['entry_list'] = entry_list
return render_to_response(template_name, context, context_instance=RequestContext(request))
def entries_by_category(request, category):
try:
post_category = Category.objects.get(slug=category)
except ObjectDoesNotExist:
post_category = None
if post_category: entry_list = Post.objects.filter(postcategory__category=post_category.id, publish=True)
return entry_list
In the template:
<div class="pagination" align="center">
{% for page in page_range %}
<a href="/{% if category %}category/{{ category }}/{% endif %}{% if author %}author/{{ author }}/{% endif %}{% if date %}date/{{ date }}/{% endif %}?page={{ page }}">{{ page }}</a>
{% endfor %}
</div>
And for what it's worth, although it's probably obvious, these are the corresponding patterns in my urls.py:
url(r'^category/(?P.*?)/*$', views.list, name='entry_list'),
url(r'^author/(?P.*?)/*$', views.list, name='entry_list'),
url(r'^date/(?P.*?)/*$', views.list, name='entry_list'),
url(r'^$', views.list, name='entry_list'),
Comment by
Malcolm Tredinnick
on Oct 02, 2008:
I'm guessing you left some keyword arguments out of the URL patterns, since, as written, they will always pass "category" and "username", never "date". Or maybe I'm missing something.
However, the bit that did jump out here is using list() as a function name. Since that's also a Python builtin, at some point in the future you'll accidentally call list() inside that module to convert a tuple to a list and spend half an hour debugging the problem. Worth programming defensively here and choosing a different name from the start, I suspect.
Comment by
Paul Kenjora
on Oct 08, 2008:
Have you considered implementing pagination purely template side. A template tag would do the trick. Queries are conserved and the code is much more portable.
http://blog.awarelabs.com/?p=29

