Django-rest-framework: IndexError for CursorPagination lorsque le jeu de requêtes change

Créé le 11 mars 2019  ·  4Commentaires  ·  Source: encode/django-rest-framework

Liste de contrôle

  • [X] J'ai vérifié que ce problème existe avec la branche master du framework Django REST.
  • [x] J'ai recherché des problèmes similaires dans les tickets ouverts et fermés et je ne trouve pas de doublon.
  • [x] Ce n'est pas une question d'utilisation. (Ceux-ci devraient plutôt être dirigés vers le groupe de discussion .)
  • [x] Cela ne peut pas être traité comme une bibliothèque tierce. (Nous préférons que les nouvelles fonctionnalités se présentent sous la forme de bibliothèques tierces dans la mesure du possible.)
  • [x] J'ai réduit le problème au cas le plus simple possible.
  • [x] J'ai inclus un test d'échec en tant que demande d'extraction. (Si vous ne pouvez pas le faire, nous pouvons toujours accepter le problème.)

Étapes à reproduire

  1. Activer la pagination du curseur
  2. Faire suffisamment d'éléments pour qu'il y ait une pagination
  3. Aller à la page 2
  4. Supprimer tous les éléments dans le shell
  5. Actualiser la page
  6. Voir l'erreur

Comportement attendu

Pour être honnête, je ne suis pas sûr, peut-être une page vide.

Comportement réel

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

Commentaire le plus utile

Merci @ewjoachim et @tomchristie

Tous les 4 commentaires

Je vais essayer de m'y mettre. S'il n'y a pas de nouvelles de moi d'ici le 15 avril, considérez que je n'y suis plus.

Pour mémoire, je ne peux pas reproduire en suivant les étapes exactes du ticket, mais si j'essaie de revenir à la page 1, j'ai le même retraçage.

Ajout d'une info : la pagination du curseur peut avoir 3 paramètres : position, offset et curseur. Le bogue est déclenché lorsque :

  • Vous êtes sur une page qui ne contient plus d'objets, car ils ont été supprimés (cela fonctionne et renvoie une liste vide)
  • Le lien vers la page précédente, même après rechargement, comporte un curseur avec un décalage et sans position.
  • Suivre ce lien mène à un 500

C'est parce que l'attribut self.page est vide, aucun élément "unique" n'est supposé être dans la page, la page est supposée contenir uniquement des éléments qui ont la même position, et donc l'algorithme se résout à utiliser un décalage -commande basée sur.

Le commentaire suivant :

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

... englobe l'erreur. Cette hypothèse est fausse si la page est vide.

Corriger la logique et dire à l'algorithme de vérifier si la page est vide, puis de définir la position sur previous_position / next_position est suffisant pour se débarrasser de ce bogue.

Les relations publiques suivront.

Merci @ewjoachim et @tomchristie

Cette page vous a été utile?
0 / 5 - 0 notes