Python Django Rest Framework UnorderedObjectListWarning

83

Ich habe ein Upgrade von Django 1.10.4 auf 1.11.1 durchgeführt und plötzlich erhalte ich eine Menge dieser Meldungen, wenn ich meine Tests durchführe:

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)

Ich habe das auf das Django-Paginierungsmodul zurückgeführt: https://github.com/django/django/blob/master/django/core/paginator.py#L100

Es scheint mit meinem Queryset-Code zu tun zu haben:

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

Wie finde ich weitere Details zu dieser Warnung? Es scheint, dass ich order_by(id)am Ende jedes Filters ein hinzufügen muss, aber ich kann anscheinend nicht finden, welcher Code das Hinzufügen von order_by benötigt (da die Warnung keinen Stack-Trace zurückgibt und dies während meines Tests zufällig geschieht Lauf).

Vielen Dank!

Bearbeiten:

Also mit @KlausD. Tipp zur Ausführlichkeit: Ich habe mir einen Test angesehen, der diesen Fehler verursacht hat:

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

Dies geht an, OrderViewSetaber keines der Dinge in get_queryset verursacht es und nichts in der Serializer-Klasse verursacht es. Ich habe andere Tests, die denselben Code verwenden, um / api / orders abzurufen, und diese verursachen ihn nicht .... Was macht DRF nach get_queryset?

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

Wenn ich einen Traceback in die Paginierung einbaue, erhalte ich eine ganze Reihe von Informationen zum Django-Rest-Framework, aber nichts, was darauf hindeutet, welche meiner Abfragen die Bestellwarnung auslöst.

Denise Mauldin
quelle
1
Normalerweise sollte es leicht sein, den Namen des Tests zu finden, der die Warnung verursacht. Vielleicht möchten Sie Tests mit Ausführlichkeit durchführen ( -v 2bei den meisten Testläufern)
Klaus D.
Danke @KlausD. Das ist eine hilfreiche Erinnerung.
Denise Mauldin
1
Sieht aus für Abfragen , wo Sie eine tun offsetund limitdoch nichtorder_by
gipsy
Danke @gipsy. Ich habe keine von denen ...
Denise Mauldin

Antworten:

131

Also, um diese zu beheben ich hatte all die finden all, offset, filterund limitKlauseln und fügen Sie eine order_byihnen Klausel. Einige habe ich durch Hinzufügen einer Standardreihenfolge behoben:

class Meta:
   ordering = ['-id']

In den ViewSets für Django Rest Framework (app / apiviews.py) musste ich alle get_querysetMethoden aktualisieren , da das Hinzufügen einer Standardreihenfolge nicht zu funktionieren schien.

Hoffe das hilft jemand anderem. :) :)

Denise Mauldin
quelle
2
Genial, wusste nicht, dass DRF das Modell liest, um auch zu bestellen <3
Amir Savand
Ich habe eine Standardbestellung in meinem Modell, erhalte jedoch weiterhin die folgende Warnung: |
Ariel
Mein Fehler. Ich hatte eine Bestellung in der übergeordneten Klasse, aber ich habe das Meta-Attribut überschrieben, ohne es ordnungsgemäß zu unterordnen, wie in den Dokumenten beschrieben , und in der untergeordneten Klasse 'Meta hatte ich keine Bestellung, sodass der Wert der übergeordneten Klasse verloren ging.
Ariel
1
Beachten Sie, dass Sie die -In- ordering = ['-id']Reihenfolge Ihrer Abfrage in absteigender Reihenfolge hinzufügen .
Elrond unterstützt Monica
49

Ich habe diese Warnung erhalten, als ich objects.all () in meiner view.py verwendet habe

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

Um dies zu beheben, habe ich meinen Code geändert in:

profile_list = Profile.objects.get_queryset().order_by('id')
paginator = Paginator(profile_list, 25)
Rajiv Sharma
quelle
1
Ich denke es sollte sein Profile.objects.all().order_by('id').. zumindest funktioniert das bei mir, sonst bekomme ichAttributeError: type object 'Profile' has no attribute 'get_queryset'
radtek
8

Lassen Sie mich eine aktualisierte Antwort auf neue Entwicklungen geben ...

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

Die Standardreihenfolge des UserModells wurde in Django entfernt. Wenn Sie sich aufgrund eines Upgrades auf dieser Seite befanden, ist dies sehr wahrscheinlich mit dieser Änderung verbunden.

Es gibt zwei Versionen dieses Problems, mit denen Sie sich möglicherweise befassen.

  1. Ihr eigenes Modell hat keine Standardbestellung Meta(siehe akzeptierte Antwort)
  2. Sie verwenden ein Modell aus einer App, die Sie als Abhängigkeit verwenden, ohne Standardreihenfolge

Da das Django- UserModell selbst buchstäblich nicht der Reihenfolge entspricht, ist es sehr klar, dass das zweite Szenario nicht gelöst werden kann, indem die Betreuer dieser Abhängigkeiten gebeten werden, eine Standardreihenfolge einzugeben. Okay, jetzt müssen Sie entweder das Modell überschreiben, das für Ihre Aktivitäten verwendet wird (manchmal eine gute Idee, aber nicht gut, um ein so kleines Problem zu lösen).

Sie müssen es also auf Ansichtsebene ansprechen. Sie möchten auch etwas tun, das mit jeder von Ihnen angewendeten Filterklasse gut funktioniert. Stellen Sie dazu den orderingParameter der Ansicht ein .

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

Siehe auch Gibt es eine Django List View-Modellsortierung?

AlanSE
quelle
0

Aktualisieren Sie stattdessen die Modell-Metaklasse.

class UsefulModel(models.Model):
    
    class Meta:
        ordering='-created' # for example

Sie können die Reihenfolge weiterhin über das Ansichtsattribut 'Bestellung' überschreiben . Dies wurde zuvor von AlanSE empfohlen .

class UsefulView(ListView):
    ordering = ['-created']
Ahmed Shehab
quelle
0

In meinem Fall musste ich order_by('id')statt hinzufügen ordering.

class IntakeCaseViewSet(viewsets.ModelViewSet):
    schema = None
    queryset = IntakeCase.objects.all().order_by('id')
Paul Schreiber
quelle
-2

Das einzuschließen hat bei mir nicht funktioniert.

class Meta:
   ordering = ['-id']

Das Ändern von get_queryset (self) und das Sortieren der Liste mit .order_by ('id') hat dies jedoch getan. Vielleicht hat es funktioniert, weil ich Filter verwende, ich weiß es nicht

class MyView(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MySerializerSerializer

    def get_queryset(self):
        user = self.request.user
        return MyModel.objects.filter(owner=user).order_by('id')
Malinoski
quelle