Python Django Rest Framework UnorderedObjectListWarning


88

Zaktualizowałem Django z wersji 1.10.4 do 1.11.1 i nagle otrzymuję mnóstwo takich komunikatów, gdy uruchamiam testy:

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)

Prześledziłem to z powrotem do modułu paginacji Django: https://github.com/django/django/blob/master/django/core/paginator.py#L100

Wydaje się, że jest to związane z kodem mojego zestawu zapytań:

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

Jak mogę znaleźć więcej szczegółów na temat tego ostrzeżenia? Wygląda na to, że muszę dodać order_by(id)na końcu każdego filtru, ale nie mogę znaleźć kodu, który wymaga dodania polecenia order_by (ponieważ ostrzeżenie nie zwraca śladu stosu i dzieje się to losowo podczas mojego testu biegać).

Dzięki!

Edytować:

Więc używając @KlausD. szczegółowość wskazówka, spojrzałem na test powodujący ten błąd:

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

To idzie, OrderViewSetale żadna z rzeczy w get_queryset nie powoduje tego i nic w klasie serializatora nie powoduje tego. Mam inne testy, które używają tego samego kodu do pobierania / api / zamówień i nie powodują tego… Co robi DRF po get_queryset?

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

Jeśli wstawię śledzenie do paginacji, otrzymam całą masę rzeczy związanych z frameworkiem django rest, ale nic, co wskazuje, które z moich zapytań wyzwala ostrzeżenie o zamówieniu.


1
Zwykle powinno być łatwe do znalezienia na podstawie nazwy testu, który powoduje ostrzeżenie. Możesz chcieć uruchomić testy z szczegółowością ( -v 2na większości testerów)
Klaus D.

Dzięki @KlausD. to pomocne przypomnienie.
Denise Mauldin

1
Szuka zapytaniami gdzie robisz offseta limitjednak nieorder_by
gipsy

Dzięki @gipsy. Nie mam żadnego z nich ....
Denise Mauldin

Odpowiedzi:


138

Tak więc w celu ustalenia tego musiałem znaleźć wszystkie all, offset, filteroraz limitklauzule i dodać order_byklauzulę do nich. Niektóre naprawiłem, dodając domyślną kolejność:

class Meta:
   ordering = ['-id']

W ViewSets for Django Rest Framework (app / apiviews.py) musiałem zaktualizować wszystkie get_querysetmetody, ponieważ dodanie domyślnej kolejności nie działało.

Mam nadzieję, że to pomoże komuś innemu. :)


2
Niesamowite, nie wiedziałem, że DRF również czyta model do zamówienia <3
Amir Savand

Mam domyślną kolejność w moim modelu, ale nadal otrzymuję ostrzeżenie: |
Ariel

Mój błąd. Miałem porządkowanie w klasie nadrzędnej, ale przesłoniłem atrybut Meta bez odpowiedniego podklasy zgodnie z opisem w dokumentacji , aw klasie podrzędnej „Meta nie miałem uporządkowania, więc wartość od rodzica została utracona.
Ariel

1
Zwróć uwagę, że dodanie -w ordering = ['-id']zamówieniach zapytania w porządku malejącym.
Elrond wspiera Monikę

50

Otrzymałem to ostrzeżenie, gdy użyłem objects.all () w moim view.py

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

aby to naprawić, zmieniłem kod na:

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

1
Myślę, że powinno być Profile.objects.all().order_by('id').. przynajmniej to działa u mnie inaczej dostajęAttributeError: type object 'Profile' has no attribute 'get_queryset'
radtek

9

Pozwólcie, że udzielę odpowiedzi zaktualizowanej o nowe osiągnięcia ...

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

Domyślna kolejność Usermodelu została usunięta w Django. Jeśli znalazłeś się na tej stronie z powodu aktualizacji, najprawdopodobniej jest to związane z tą zmianą.

Istnieją 2 wersje tego problemu, z którymi możesz mieć do czynienia.

  1. Twój model nie ma domyślnej kolejności Meta(patrz zaakceptowana odpowiedź)
  2. używasz modelu z aplikacji, której używasz jako zależności, która nie ma domyślnej kolejności

Ponieważ dosłownie Usersam model Django nie przestrzega kolejności, jest bardzo jasne, że drugiego scenariusza nie można rozwiązać, prosząc opiekunów tych zależności o ustawienie domyślnej kolejności. Okay, więc teraz albo musisz zastąpić model używany do wszystkiego, co robisz (czasami jest to dobry pomysł, ale nie jest dobry do rozwiązania tak drobnego problemu).

Pozostaje więc rozwiązanie tego problemu na poziomie widoku. Chcesz także zrobić coś, co będzie dobrze pasować do każdej zastosowanej klasy filtru porządkowania. W tym celu ustaw orderingparametr widoku .

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

Zobacz także Czy istnieje sortowanie modeli w widoku listy Django?



1

W moim przypadku order_by('id')zamiast tego musiałem dodać ordering.

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

0

Zaktualizuj zamiast tego klasę meta modelu.

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

nadal możesz zmienić kolejność w atrybucie „ordering” widoku „ordering”. Zgodnie z wcześniejszymi zaleceniami AlanSE .

class UsefulView(ListView):
    ordering = ['-created']

-2

W tym to nie zadziałało dla mnie.

class Meta:
   ordering = ['-id']

Ale zmiana get_queryset (self) i posortowanie listy za pomocą .order_by ('id') zrobiło. Może zadziałało, ponieważ używam filtrów, nie wiem

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')
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.