views:

997

answers:

2

I'm currently developing a Django application which will make use of the infamous "pagination" technique. I'm trying to figure out how the django.core.paginator module works.

I have an application with a Question model. I will be listing all of the questions using this paginator. There will be 20 questions per page.

def show_question(question_pk):
    questions = Question.objects.all()
    paginator = Paginator(questions, 20)
    page      = ... # Somehow figure out which page the question is on
    return render_to_response('show_question.html', { 'page' : page })

In the view, where I list the different pages as "... 2, 3, 4, 5, 6, ..." I want to highlight the current page somehow, like many pages do.

There are really two things I want to know:

  1. How do I make Django figure out which page the question is located at?
  2. How would I write my template to properly "highlight" the currently visited page?

EDIT: Sorry, I forgot part of this question. I would also like any page except for the current one to be a link to /questions/{{ that_page.start_index }}. So basically every page link would link to the first question on that page.

+1  A: 

django-pagination should do what you want and comes wrapped in a pretty package you can just plug-in and use. It essentially moves the code from your views to the templates and a middleware.

EDIT: I just saw your edit. You can get the current objects on a page using {% autopaginate object_list %}, which replaces object_list with the current objects for any given page. You can iterate through it and if you want the first, you should be able to treat it like a list and do object_list[0].

If you want to keep this within your views, you could do something like this:

def show_question(question_pk):
    questions = Question.objects.all()
    paginator = Paginator(questions, 20)
    return render_to_response('show_question.html', { 'page' : paginator })

Within your template, you can access the current page you're on by doing:

# Gives you the starting index for that page.
# For example, 5 objects, and you're on the second page. 
# start_index will be 3.
page.start_index

# You can access the current page number with:
# 1-based index
page.number

With that, you should be able to do everything you need. There are a couple good examples here.

Nick Presta
Thanks for your comment. However, to me it seems that django-pagination does nothing more than the built-in pagination stuff, but simply moves the logic from the code into the templates and a middleware. Is it so?
Deniz Dogan
Essentially, yes. I updated my answer if you want to keep your pagination login inside your view.
Nick Presta
+1  A: 

Hmm... I see from your comment that you don't want to do the ol' GET parameter, which is what django.core.paginator was written for using. To do what you want, I can think of no better way than to precompute the page that each question is on. As an example, your view will end up being something like:

ITEMS_PER_PAGE = 20
def show_question(question_pk):
    questions = Question.objects.all()
    for index, question in enumerate(questions):
        question.page = ((index - 1) / ITEMS_PER_PAGE) + 1
    paginator = Paginator(questions, ITEMS_PER_PAGE)
    page = paginator.page(questions.get(pk=question_pk).page)
    return render_to_response('show_question.html', { 'page' : page })

To highlight the current page in the template, you'd do something like

{% for i in page.paginator.page_range %}
    {% ifequal i page.number %}
        <!-- Do something special for this page -->
    {% else %}
        <!-- All the other pages -->
    {% endifequal %}
{% endfor %}

As for the items, you'll have two different object_lists to work with...

page.object_list

will be the objects in the current page and

page.paginator.object_list

will be all objects, regardless of page. Each of those items will have a "page" variable that will tell you which page they're on.

That all said, what you're doing sounds unconventional. You may want to rethink, but either way, good luck.

uzi
Oh boy, oh boy! `page.paginator.object_list[i].page` sounds like it's probably exactly what I was looking for! I'll check that out immediately. Thanks!
Deniz Dogan