Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

Django, at least from version 1.2, allows us to complete this task by using pure default pagination template tags.

{% for page in article_list.paginator.page_range %}
  {% if page == article_list.number %}
    {{ page }}
  {% else %}
    <a href="/page{{ page }}">{{ page }}</a>
  {% endif %}
{% endfor %}

Where article_list is instance of

paginator = Paginator(article_list, 20)
    try:
        article_list = paginator.page(int(page))
    except (EmptyPage, InvalidPage):
        article_list = paginator.page(paginator.num_pages)

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top