1

I'm trying to create a paging mechanism to page through a query. Going forward is not an issue. Going to a previous page seems to be non-trivial though.

What I have so far is this (why do I have the feeling that it should be simpler?):

cursor_urlsafe = self.request.get('cursor', None)
rev = bool(self.request.get('rev', None))
cursor = ndb.Cursor(urlsafe=cursor_urlsafe)
if rev:
    next_query = Shot.query(Shot.schedule_key == schedule.key).order(Shot.date_created)
    cursor = cursor.reversed()
else:
    next_query = Shot.query(Shot.schedule_key == schedule.key).order(-Shot.date_created)

shots, next_cursor, more = next_query.fetch_page(PAGE_LENGTH, start_cursor=cursor)

if rev:
    shots.sort(key=lambda x: -x.date_created_epoch)

next_cursor_url_safe = next_cursor.urlsafe() if next_cursor else None
template_params = {
    'shots': shots,
    'next_cursor': next_cursor_url_safe,
    'prev_cursor': next_cursor_url_safe if cursor_urlsafe else None
}

and on the client side:

<a href="/schedule/{{ s.id }}?cursor={{ prev_cursor }}&rev=true">Previous</a><br>
<a href="/schedule/{{ s.id }}?cursor={{ next_cursor }}">Next</a>

This sort of works. The only problem is that when the user "changes direction" (pages back) it brings him to the page he is on again, and only after another click on previous it goes to the previous page.

So if click, Previous and then Next I remain on the same page all the time.

Please advise.

Dan McGrath
  • 41,220
  • 11
  • 99
  • 130
MeLight
  • 5,454
  • 4
  • 43
  • 67

2 Answers2

0

There are a few strategies you can adopt. Storing previous cursors - See https://p.ota.to/blog/2013/4/pagination-with-cursors-in-the-app-engine-datastore/ or alternately search SO for another approach What is the correct way to get the previous page of results given an NDB cursor?

Community
  • 1
  • 1
Tim Hoffman
  • 12,976
  • 1
  • 17
  • 29
  • 1
    Correct me if I'm wrong, but it feels like a major design fail if I need to "adopt strategies" in order to implement a simple paging functionality :( – MeLight Oct 18 '15 at 07:08
  • You are dealing with a No SQL environment. I would take up the "design deficiency" with google. Both of the links provide you with a solution however. You do have to step outside of the SQL world and understand what is going on here. Look at DynamoDB on AWS similar strategies are required for reverse pagination. See http://stackoverflow.com/questions/14396346/pagination-in-dynamodb – Tim Hoffman Oct 18 '15 at 11:30
0

One solution is to have the client keep a list of cursors as they move forward. When they page backwards, use the previous cursor in the list. Cursors on the backend can be exported to a string. In Java, you use the toUrlSafe method. There's probably an equivalent for Python.

When using the previous cursor, I recommend removing the last cursor in the list so that a fresh instance of it gets created when the user pages forward again. Then again, that depends on how often the data will change. If the data seldom changes, you can skip removing cursors from the list and just use the cached ones instead to speed up time on the backend.

Johann
  • 27,536
  • 39
  • 165
  • 279