web-dev-qa-db-fra.com

Python Django Rest Framework UnorderedObjectListWarning

Je suis passé de Django 1.10.4 à 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)

J'ai retracé cela jusqu'au Django Module de pagination: https://github.com/Django/django/blob/master/Django/core/paginator.py#L10

Cela semble lié à mon code de requête:

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

Comment puis-je trouver plus de détails sur cet avertissement? Il semble que j’ai besoin d’ajouter un order_by(id) à la fin de chaque filtre, mais je n'arrive pas à trouver quel code a besoin de order_by (car l’avertissement ne renvoie pas de trace de pile et donc cela se produit de manière aléatoire pendant mon test).

Merci!

Modifier:

Donc, en utilisant @ KlausD. Astuce de verbosité, j'ai regardé un test provoquant 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 sérialiseur ne le cause. J'ai d'autres tests qui utilisent le même code pour obtenir/api/orders et ceux-ci ne le causent pas .... Que fait DRF après get_queryset?

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

Si je mets une trace dans la pagination, je reçois une foule de choses liées au cadre de repos Django), mais rien qui pointe vers lequel de mes requêtes déclenche l'avertissement d'ordre.

57
Denise Mauldin

Donc, pour résoudre ce problème, je devais trouver toutes les clauses all, offset, filter et limit et ajouter un order_by clause à eux. Certains j'ai corrigé en ajoutant une commande par défaut:

class Meta:
   ordering = ['-id']

Dans les ViewSets pour Django Rest Framework (app/apiviews.py), je devais mettre à jour tous les get_queryset méthodes comme l'ajout d'un ordre par défaut ne semble pas fonctionner.

J'espère que ceci aide quelqu'un d'autre. :)

83
Denise Mauldin

Je recevais 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 changé mon code en:

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

Une autre option consiste à ajouter OrderingFilter

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

3
Michael Benin

Permettez-moi de donner une réponse mise à jour aux nouveaux développements ...

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

L'ordre par défaut du modèle User a été supprimé de Django. Si vous vous êtes retrouvé sur cette page à cause d'une mise à niveau, il est très probablement lié à ce changement.

Il existe 2 versions de ce problème que vous pourriez traiter.

  1. votre propre modèle n'a pas de classement par défaut dans sa Meta (voir la réponse acceptée)
  2. vous utilisez un modèle d'une application que vous utilisez en tant que dépendance sans ordre par défaut

Etant donné que le modèle Django User lui-même ne respecte pas les commandes, il est très clair que le second scénario ne peut pas être résolu en demandant aux responsables de ces dépendances de définir des commandes par défaut. Alors, maintenant, vous devez soit remplacer le modèle utilisé pour quoi que vous fassiez (parfois une bonne idée, mais ce n’est pas bon pour traiter un problème aussi mineur).

Il ne vous reste donc plus qu'à vous en occuper au niveau de la vue. Vous voulez également faire quelque chose qui fonctionnera bien avec n'importe quelle classe de filtre de classement que vous aurez appliquée. Pour cela, définissez le paramètre ordering de la vue.

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

Voir aussi Existe-t-il Django Tri par modèle de vue?

1
AlanSE