Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get previous and next objects from a filtered, ordered queryset?

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.

like image 526
Michael Dunn Avatar asked Nov 07 '09 08:11

Michael Dunn


People also ask

What does Queryset filter return?

filter() Returns a new QuerySet containing objects that match the given lookup parameters. The lookup parameters ( **kwargs ) should be in the format described in Field lookups below. Multiple parameters are joined via AND in the underlying SQL statement.

Can you filter a Queryset?

Yes, you can reuse existing querysets. This is not really making anything faster though, in fact, this code block won't even execute a query against the database because Django QuerySets are lazily evaluated. What I means is that it won't send the query to the database until you actually need the values.

Which can be used to retrieve an object directly instead of a Queryset?

Retrieving Single Objects from QuerySets We can do this using the get() method. The get() returns the single object directly. Let's see the following example. As we can see in both examples, we get the single object not a queryset of a single object.


1 Answers

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.

like image 116
T. Stone Avatar answered Nov 15 '22 09:11

T. Stone