Django-rest-framework: IndexError для CursorPagination при изменении набора запросов

Созданный на 11 мар. 2019  ·  4Комментарии  ·  Источник: encode/django-rest-framework

Контрольный список

  • [X] Я убедился, что эта проблема существует в ветви master платформы Django REST.
  • [x] Я искал похожие проблемы как в открытых, так и в закрытых тикетах и ​​не могу найти дубликатов.
  • [x] Это не вопрос использования. (Вместо этого их следует направлять в дискуссионную группу .)
  • [x] Это не может рассматриваться как сторонняя библиотека. (Мы предпочитаем, чтобы новые функции были в форме сторонних библиотек, где это возможно.)
  • [x] Я свел проблему к простейшему случаю.
  • [x] Я включил неудачный тест в качестве запроса на вытягивание. (Если вы не можете сделать это, мы все равно можем принять проблему.)

Действия по воспроизведению

  1. Включить CursorPagination
  2. Сделайте достаточно элементов, чтобы была разбивка на страницы
  3. Перейти на страницу 2
  4. Удалить все элементы в оболочке
  5. Обновите страницу
  6. Увидеть ошибку

Ожидаемое поведение

Если честно не уверен, может и пустая страница.

Фактическое поведение

Traceback (most recent call last):
  File "/var/env/lib/python3.6/site-packages/django/contrib/staticfiles/handlers.py", line 65, in __call__
    return self.application(environ, start_response)
  File "/var/env/lib/python3.6/site-packages/django/core/handlers/wsgi.py", line 142, in __call__
    response = self.get_response(request)
  File "/var/env/lib/python3.6/site-packages/django/core/handlers/base.py", line 78, in get_response
    response = self._middleware_chain(request)
  File "/var/env/lib/python3.6/site-packages/django/core/handlers/exception.py", line 36, in inner
    response = response_for_exception(request, exc)
  File "/var/env/lib/python3.6/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/var/env/lib/python3.6/site-packages/django/core/handlers/exception.py", line 125, in handle_uncaught_exception
    return debug.technical_500_response(request, *exc_info)
  File "/var/env/lib/python3.6/site-packages/django_extensions/management/technical_response.py", line 37, in null_technical_500_response
    six.reraise(exc_type, exc_value, tb)
  File "/var/env/lib/python3.6/site-packages/six.py", line 692, in reraise
    raise value.with_traceback(tb)
  File "/var/env/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/var/env/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/var/env/lib/python3.6/site-packages/django/core/handlers/base.py", line 124, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/var/env/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/var/env/lib/python3.6/site-packages/rest_framework/viewsets.py", line 116, in view
    return self.dispatch(request, *args, **kwargs)
  File "/var/env/lib/python3.6/site-packages/rest_framework/views.py", line 495, in dispatch
    response = self.handle_exception(exc)
  File "/var/env/lib/python3.6/site-packages/rest_framework/views.py", line 455, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/var/env/lib/python3.6/site-packages/rest_framework/views.py", line 492, in dispatch
    response = handler(request, *args, **kwargs)
  File "/var/env/lib/python3.6/site-packages/rest_framework/mixins.py", line 45, in list
    return self.get_paginated_response(serializer.data)
  File "/var/env/lib/python3.6/site-packages/rest_framework/generics.py", line 180, in get_paginated_response
    return self.paginator.get_paginated_response(data)
  File "/var/env/lib/python3.6/site-packages/rest_framework/pagination.py", line 781, in get_paginated_response
    ('previous', self.get_previous_link()),
  File "/var/env/lib/python3.6/site-packages/rest_framework/pagination.py", line 643, in get_previous_link
    compare = self._get_position_from_instance(self.page[0], self.ordering)
IndexError: list index out of range

Самый полезный комментарий

Спасибо @ewjoachim и @tomchristie 👍

Все 4 Комментарий

Я собираюсь попробовать и попробовать. Если до 15 апреля от меня не будет новостей, считайте, что меня в нем больше нет.

Для записи, я не могу воспроизвести, следуя точным шагам тикета, но если я попытаюсь вернуться на страницу 1, то у меня будет такая же трассировка.

Добавляем некоторую информацию: пагинация курсора может иметь 3 параметра: положение, смещение и курсор. Ошибка срабатывает, когда:

  • Вы находитесь на странице, которая больше не содержит объектов, потому что они были удалены (это работает и возвращает пустой список)
  • Ссылка на предыдущую страницу, даже после перезагрузки, включает курсор со смещением и без позиции.
  • Переход по этой ссылке приводит к 500

Это связано с тем, что атрибут self.page пуст, предполагается, что на странице нет «уникального» элемента, предполагается, что страница содержит только элементы, которые имеют такую ​​же позицию, и, таким образом, алгоритм разрешает использование смещения заказ на основе.

Следующий комментарий:

https://github.com/encode/django-rest-framework/blob/29cbe574a384c3bcc09434a3a9c5ff0cb7576b99/rest_framework/pagination.py#L615

... заключает в себе ошибку. Это предположение неверно, если страница пуста.

Исправления логики и указания алгоритму проверять, пуста ли страница, а затем устанавливать позицию на previous_position / next_position , достаточно, чтобы избавиться от этой ошибки.

PR последует.

Спасибо @ewjoachim и @tomchristie 👍

Была ли эта страница полезной?
0 / 5 - 0 рейтинги