diff --git a/lms/djangoapps/course_api/tests/test_views.py b/lms/djangoapps/course_api/tests/test_views.py index 0321e93dbb..9ddc4af1f3 100644 --- a/lms/djangoapps/course_api/tests/test_views.py +++ b/lms/djangoapps/course_api/tests/test_views.py @@ -527,3 +527,24 @@ class LazyPageNumberPaginationTestCase(TestCase): paginated_queryset = pagination.paginate_queryset(even_numbers_lazy_sequence, request) paginated_response = pagination.get_paginated_response(paginated_queryset) self.assertDictEqual(expected_response, paginated_response.data) + + def test_not_found_error_for_invalid_page(self): + number_sequence = range(20) + even_numbers_lazy_sequence = LazySequence( + ( + number for number in number_sequence + if (number % 2) == 0 + ), + est_len=len(number_sequence) + ) + + request = RequestFactory().get('/endpoint', data={'page': 3, 'page_size': 5}) + request.query_params = {'page': 3, 'page_size': 5} + + with self.assertRaises(Exception) as exc: + pagination = LazyPageNumberPagination() + pagination.max_page_size = 5 + pagination.page_size = 5 + paginated_queryset = pagination.paginate_queryset(even_numbers_lazy_sequence, request) + pagination.get_paginated_response(paginated_queryset) + self.assertIn('Invalid page', exc.exception) diff --git a/lms/djangoapps/course_api/views.py b/lms/djangoapps/course_api/views.py index 5c507dc2ca..5606d91fd7 100644 --- a/lms/djangoapps/course_api/views.py +++ b/lms/djangoapps/course_api/views.py @@ -4,9 +4,11 @@ Course API Views from django.core.exceptions import ValidationError +from django.core.paginator import InvalidPage from edx_rest_framework_extensions.paginators import NamespacedPageNumberPagination from rest_framework.generics import ListAPIView, RetrieveAPIView from rest_framework.throttling import UserRateThrottle +from rest_framework.exceptions import NotFound from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin, view_auth_classes @@ -175,6 +177,20 @@ class LazyPageNumberPagination(NamespacedPageNumberPagination): del self.page.paginator.__dict__['count'] del self.page.paginator.__dict__['num_pages'] + # Paginate queryset function is using cached number of pages and sometime after + # deleting from cache when we recalculate number of pages are different and it raises + # EmptyPage error while accessing the previous page link. So we are catching that exception + # and raising 404. For more detail checkout PROD-1222 + page_number = self.request.query_params.get(self.page_query_param, 1) + try: + self.page.paginator.validate_number(page_number) + except InvalidPage as exc: + msg = self.invalid_page_message.format( + page_number=page_number, message=str(exc) + ) + self.page.number = self.page.paginator.num_pages + raise NotFound(msg) + return super(LazyPageNumberPagination, self).get_paginated_response(data)