131 votes

Cadre de repos Python Django UnorderedObjectListWarning

J'ai effectué une mise à niveau de Django 1.10.4 vers 1.11.1 et, tout à coup, je reçois une tonne de ces messages lorsque je lance mes tests :

lib/python3.5/site-packages/rest_framework/pagination.py:208:
UnorderedObjectListWarning: 
Pagination may yield inconsistent results with an unordered object_list: 
<QuerySet [<Group: Requester>]>
paginator = self.django_paginator_class(queryset, page_size)

Je suis remonté jusqu'au module Django Pagination : https://github.com/django/django/blob/master/django/core/paginator.py#L100

Il semble que cela soit lié à mon code queryset :

return get_user_model().objects.filter(id=self.request.user.id)

Comment puis-je trouver plus de détails sur cet avertissement ? Il semblerait que je doive ajouter un fichier order_by(id) à la fin de chaque filtre, mais je n'arrive pas à trouver quel code a besoin de l'ajout de order_by (parce que l'avertissement ne renvoie pas de trace de la pile et qu'il se produit de manière aléatoire pendant mon test).

Gracias.

Edit :

Donc en utilisant l'astuce de verbosité de @KlausD., j'ai regardé un test causant cette erreur :

response = self.client.get('/api/orders/')

Ceci va à OrderViewSet mais aucune des choses dans get_queryset ne le cause et rien dans la classe serializer ne le cause. J'ai d'autres tests qui utilisent le même code pour obtenir /api/orders et ceux-ci ne le provoquent pas..... Que fait la DRF après get_queryset ?

https://github.com/encode/django-rest-framework/blob/master/rest_framework/pagination.py#L166

Si je mets une traceback dans la pagination, j'obtiens tout un tas de choses liées au django rest framework mais rien qui permette de savoir laquelle de mes requêtes déclenche l'avertissement de commande.

1 votes

En général, il devrait être facile à trouver par le nom du test qui cause l'avertissement. Vous pouvez vouloir exécuter les tests avec de la verbosité ( -v 2 sur la plupart des exécutants de test)

0 votes

Merci @KlausD. C'est un rappel utile.

1 votes

Recherche les requêtes où vous faites un offset y limit mais non order_by

206voto

Denise Mauldin Points 1688

Donc, pour résoudre ce problème, j'ai dû trouver tous les éléments suivants all , offset , filter et limit et ajouter une clause order_by clause pour eux. J'en ai corrigé certains en ajoutant un ordre par défaut :

class Meta:
   ordering = ['-id']

Dans le cadre ViewSets for Django Rest (app/apiviews.py), j'ai dû mettre à jour tous les fichiers get_queryset car l'ajout d'une commande par défaut ne semble pas fonctionner.

J'espère que cela aidera quelqu'un d'autre :)

2 votes

Génial, je ne savais pas que DRF lisait le modèle pour commander aussi <3

0 votes

J'ai bien une commande par défaut dans mon modèle mais je reçois toujours cet avertissement :|

1 votes

Mon erreur. J'avais la commande dans la classe parent, mais j'ai remplacé l'attribut Meta sans en le sous-classant correctement comme décrit dans la documentation. Dans la Meta de la classe enfant, il n'y avait pas d'ordre, et la valeur du parent était donc perdue.

74voto

Rajiv Sharma Points 1786

J'ai reçu cet avertissement lorsque j'ai utilisé objects.all() dans mon view.py.

profile_list = Profile.objects.all()
paginator = Paginator(profile_list, 25)

Pour résoudre ce problème, j'ai modifié mon code en :

profile_list = Profile.objects.get_queryset().order_by('id')
paginator = Paginator(profile_list, 25)

2 votes

Je pense que ça devrait être Profile.objects.all().order_by('id') du moins, cela fonctionne pour moi, sinon j'obtiens AttributeError: type object 'Profile' has no attribute 'get_queryset'

19voto

Paul Schreiber Points 7214

Dans mon cas, j'ai dû ajouter order_by('id') au lieu de ordering .

class IntakeCaseViewSet(viewsets.ModelViewSet):
    schema = None
    queryset = IntakeCase.objects.all().order_by('id')

11voto

AlanSE Points 787

Permettez-moi de donner une réponse actualisée en fonction des nouveaux développements...

https://code.djangoproject.com/ticket/6089

L'ordre par défaut des User a été supprimé dans Django. Si vous vous êtes retrouvé sur cette page à cause d'une mise à jour, il est très probable que ce soit lié à ce changement.

Il existe deux versions de ce problème que vous pouvez rencontrer.

  1. votre propre modèle n'a pas d'ordre par défaut dans son Meta (voir réponse acceptée)
  2. vous utilisez un modèle d'une application que vous utilisez comme dépendance et qui n'a pas d'ordre par défaut.

Puisque littéralement le système Django User n'adhère pas à l'ordre, il est très clair que le second scénario ne peut pas être résolu en demandant aux mainteneurs de ces dépendances de mettre en place un ordre par défaut. D'accord, alors maintenant vous devez soit remplacer le modèle utilisé pour ce que vous faites (parfois une bonne idée, mais pas pour résoudre un problème aussi mineur).

Il ne reste donc plus qu'à s'attaquer au problème au niveau de la vue. Vous voulez également faire quelque chose qui fonctionnera bien avec toute classe de filtre de classement que vous avez appliquée. Pour cela, définissez le paramètre ordering paramètre.

class Reviewers(ListView):
    model = User
    paginate_by = 50
    ordering = ['username']

Voir aussi Existe-t-il un tri du modèle de la vue en liste de Django ?

0 votes

Cela devrait être la réponse acceptée :)

5voto

Michael Benin Points 1009

Une autre option consiste à ajouter OrderingFilter

http://www.django-rest-framework.org/api-guide/filtering/#orderingfilter

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X