From 1cd4f9fec1e2ebfe32d37371bf7885edd11f861f Mon Sep 17 00:00:00 2001 From: Joachim Jablon Date: Sun, 14 Apr 2019 02:08:34 +0200 Subject: [PATCH] Fix CursorPagination when objects get deleted between calls (#6504) Co-Authored-By: Tom Quinonero --- rest_framework/pagination.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/rest_framework/pagination.py b/rest_framework/pagination.py index b11d7cdf3..13c5faa81 100644 --- a/rest_framework/pagination.py +++ b/rest_framework/pagination.py @@ -589,7 +589,7 @@ class CursorPagination(BasePagination): if not self.has_next: return None - if self.cursor and self.cursor.reverse and self.cursor.offset != 0: + if self.page and self.cursor and self.cursor.reverse and self.cursor.offset != 0: # If we're reversing direction and we have an offset cursor # then we cannot use the first position we find as a marker. compare = self._get_position_from_instance(self.page[-1], self.ordering) @@ -597,12 +597,14 @@ class CursorPagination(BasePagination): compare = self.next_position offset = 0 + has_item_with_unique_position = False for item in reversed(self.page): position = self._get_position_from_instance(item, self.ordering) if position != compare: # The item in this position and the item following it # have different positions. We can use this position as # our marker. + has_item_with_unique_position = True break # The item in this position has the same position as the item @@ -611,7 +613,7 @@ class CursorPagination(BasePagination): compare = position offset += 1 - else: + if self.page and not has_item_with_unique_position: # There were no unique positions in the page. if not self.has_previous: # We are on the first page. @@ -630,6 +632,9 @@ class CursorPagination(BasePagination): offset = self.cursor.offset + self.page_size position = self.previous_position + if not self.page: + position = self.next_position + cursor = Cursor(offset=offset, reverse=False, position=position) return self.encode_cursor(cursor) @@ -637,7 +642,7 @@ class CursorPagination(BasePagination): if not self.has_previous: return None - if self.cursor and not self.cursor.reverse and self.cursor.offset != 0: + if self.page and self.cursor and not self.cursor.reverse and self.cursor.offset != 0: # If we're reversing direction and we have an offset cursor # then we cannot use the first position we find as a marker. compare = self._get_position_from_instance(self.page[0], self.ordering) @@ -645,12 +650,14 @@ class CursorPagination(BasePagination): compare = self.previous_position offset = 0 + has_item_with_unique_position = False for item in self.page: position = self._get_position_from_instance(item, self.ordering) if position != compare: # The item in this position and the item following it # have different positions. We can use this position as # our marker. + has_item_with_unique_position = True break # The item in this position has the same position as the item @@ -659,7 +666,7 @@ class CursorPagination(BasePagination): compare = position offset += 1 - else: + if self.page and not has_item_with_unique_position: # There were no unique positions in the page. if not self.has_next: # We are on the final page. @@ -678,6 +685,9 @@ class CursorPagination(BasePagination): offset = 0 position = self.next_position + if not self.page: + position = self.previous_position + cursor = Cursor(offset=offset, reverse=True, position=position) return self.encode_cursor(cursor)