views:

162

answers:

1

I have a page based on a model object, and I want to have links to the previous and next pages. I don't like my current solution because it requires evaluating the entire queryset (to get the ids list), and then two more get queries. Surely there is some way this can be done in one pass?

def get_prev_and_next_page(current_page):
    ids = list(Page.objects.values_list("id", flat=True))
    current_idx = ids.index(current_page.id)
    prev_page = Page.objects.get(id=ids[current_idx-1])
    try:
        next_page = Page.objects.get(id=ids[current_idx+1])
    except IndexError:
        next_page = Page.objects.get(id=ids[0])
    return (prev_page, next_page)

Sort order is defined in the model, so doesn't have to be handled here, but note that you can't assume that ids are sequential.

+3  A: 

Sounds like something the Paginator set to a threshold of 1 would do well at.

# Full query set...
pages = Page.objects.filter(column=somevalue)
p = Paginator(pages, 1)

# Where next page would be something like...
if p.has_next():
     p.page(p.number+1)

Documentation here and here.

T. Stone
Thanks, I was vaguely aware of the Paginator, but hadn't realized that I could use it like that (i.e. with a threshold of 1, in effect just wrapping the queryset in a Paginator object with the `has_next()`, `has_previous()` methods). The only thing missing is that I don't start at the beginning of the paginator range, but it looks like I can get this with `p.object_list.index(start_page)`.
Michael Dunn