Super simple pagination, WITHOUT using Django's Paginator object

Sep 25, 2008 Django Python

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:

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'),