Django-rest-framework: クエリセットが変更されたときのCursorPaginationのIndexError

作成日 2019年03月11日  ·  4コメント  ·  ソース: encode/django-rest-framework

チェックリスト

  • [X]その問題がDjangoRESTフレームワークのmasterブランチに対して存在することを確認しました。
  • [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件

やってみようと思います。 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 評価