Django-rest-framework: IndexError für CursorPagination, wenn sich der Abfragesatz ändert

Erstellt am 11. März 2019  ·  4Kommentare  ·  Quelle: encode/django-rest-framework

Checkliste

  • [X] Ich habe überprüft, dass dieses Problem für den master Zweig des Django REST-Frameworks besteht.
  • [x] Ich habe sowohl in offenen als auch in geschlossenen Tickets nach ähnlichen Problemen gesucht und kann kein Duplikat finden.
  • [x] Dies ist keine Verwendungsfrage. (Diese sollten stattdessen an die Diskussionsgruppe weitergeleitet werden.)
  • [x] Dies kann nicht als Bibliothek von Drittanbietern behandelt werden. (Wir bevorzugen, wenn möglich, neue Funktionen in Form von Bibliotheken von Drittanbietern .)
  • [x] Ich habe das Thema auf den einfachsten Fall reduziert.
  • [x] Ich habe einen fehlgeschlagenen Test als Pull-Request eingefügt. (Wenn Sie dazu nicht in der Lage sind, können wir das Problem trotzdem annehmen.)

Schritte zum Reproduzieren

  1. CursorPagination aktivieren
  2. Stellen Sie genügend Elemente her, die eine Paginierung aufweisen
  3. Gehen Sie zu Seite 2
  4. Löschen Sie alle Elemente in der Shell
  5. Lade die Seite neu
  6. Siehe Fehler

Erwartetes Verhalten

Ehrlich gesagt bin ich mir nicht sicher, vielleicht eine leere Seite.

Tatsächliches Verhalten

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

Hilfreichster Kommentar

Dank @ewjoachim und @tomchristie 👍

Alle 4 Kommentare

Ich werde versuchen, es zu versuchen. Wenn es bis zum 15. April keine Neuigkeiten von mir gibt, bedenke, dass ich nicht mehr dabei bin.

Fürs Protokoll kann ich nicht reproduzieren, wenn ich die genauen Schritte des Tickets befolge, aber wenn ich versuche, zu Seite 1 zurückzukehren, habe ich den gleichen Traceback.

Einige Informationen hinzufügen: Die Cursor-Paginierung kann 3 Parameter haben: Position, Offset und Cursor. Der Fehler wird ausgelöst, wenn:

  • Sie befinden sich auf einer Seite, die keine Objekte mehr enthält, da diese gelöscht wurden (dies funktioniert und gibt eine leere Liste zurück)
  • Der Link zur vorherigen Seite enthält auch nach dem erneuten Laden einen Cursor mit Offset und ohne Position.
  • Wenn Sie diesem Link folgen, gelangen Sie zu einem 500

Dies liegt daran, dass das Attribut self.page leer ist, kein "eindeutiges" Element auf der Seite vorhanden ist, die Seite nur Elemente enthält, die dieselbe Position haben, und daher wird der Algorithmus auf die Verwendung eines Offsets aufgelöst -basierte Bestellung.

Folgender Kommentar:

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

... umfasst den Fehler. Diese Annahme ist falsch, wenn die Seite leer ist.

Es reicht aus, die Logik zu korrigieren und dem Algorithmus mitzuteilen, dass er überprüfen soll, ob die Seite leer ist, und dann die Position auf previous_position / next_position , um diesen Fehler zu beheben.

PR wird folgen.

Dank @ewjoachim und @tomchristie 👍

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen