Python Django Rest Framework UnorderedObjectListWarning


88

Я перейшов з Django 1.10.4 на 1.11.1 і раптом я отримую купу цих повідомлень, коли запускаю тести:

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)

Я простежив це до модуля Pagination Django: https://github.com/django/django/blob/master/django/core/paginator.py#L100

Здається, це пов’язано з моїм кодом набору запитів:

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

Як я можу знайти докладнішу інформацію про це попередження? Здається, мені потрібно додати a order_by(id)в кінці кожного фільтра, але я, здається, не можу знайти, який код потребує доданого order_by (оскільки попередження не повертає трасування стека, і це трапляється випадково під час мого тесту бігати).

Дякую!

Редагувати:

Отже, за допомогою @KlausD. підказка, я подивився тест, який спричинив цю помилку:

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

Це стосується, OrderViewSetале жодна з речей у get_queryset не спричиняє цього, і ніщо в класі серіалізатора не викликає. У мене є інші тести, які використовують той самий код для отримання / api / замовлення, і ті не викликають його .... Що робить DRF після get_queryset?

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

Якщо я вкладаю трасування назад у пагінацію, то я отримую цілу купу речей, пов’язаних з django rest framework, але нічого, що вказує на те, який із моїх запитів ініціює попередження про замовлення.


1
Зазвичай це може бути легко знайти за назвою тесту, який викликає попередження. Можливо, ви захочете провести тести з багатослівністю ( -v 2на більшості бігунів)
Клаус Д.,

Дякую @KlausD. це корисне нагадування.
Деніз Молдін,

1
Мабуть для запитів , де ви робите offsetі , limitале неorder_by
циганка

Дякую @gipsy. У мене немає нічого з цього ...
Деніз Молдін,

Відповіді:


138

Тому для того , щоб виправити це , я повинен був знайти все all, offset, filterі limitположень і додати order_byпункт до них. Деякі з них я виправив, додавши замовлення за замовчуванням:

class Meta:
   ordering = ['-id']

У ViewSets for Django Rest Framework (app / apiviews.py) мені довелося оновити всі get_querysetметоди, оскільки додавання замовлення за замовчуванням, здавалося, не спрацювало.

Сподіваюся, це допомагає комусь іншому. :)


2
Чудово, не знав, що DRF теж читає модель для замовлення <3
Амір Саванд

У моїй моделі є замовлення за замовчуванням, але я все одно отримую таке попередження: |
Аріель

Моя помилка. У мене було замовлення в батьківському класі, але я перевизначив атрибут Meta, не належним чином підкласуючи його, як описано в документах , а в дочірньому класі 'Meta у мене не було впорядкування, тому значення з батьків було втрачено.
Аріель

1
Зверніть увагу, що додавання запиту in -в ordering = ['-id']замовлення здійснюється за спаданням.
Елронд підтримує Моніку

50

Я отримував це попередження, коли використовував objects.all () на моєму view.py

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

щоб виправити це, я змінив свій код на:

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

1
Я думаю, це повинно бути Profile.objects.all().order_by('id').. принаймні, це працює для мене, інакше я отримуюAttributeError: type object 'Profile' has no attribute 'get_queryset'
radtek

9

Дозвольте мені дати відповідь, оновлену до нових розробок ...

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

Впорядкування Userмоделі за замовчуванням було видалено в Django. Якщо ви опинились на цій сторінці через оновлення, це, швидше за все, пов’язано із цією зміною.

Існує 2 версії цієї проблеми, з якими ви можете стикатися.

  1. ваша власна модель не має замовлення за замовчуванням Meta(див. прийняту відповідь)
  2. ви використовуєте модель із програми, яку ви використовуєте як залежність, яка не має впорядкування за замовчуванням

Оскільки буквально сама Userмодель Django не відповідає упорядкуванню, цілком зрозуміло, що другий сценарій не може бути вирішений, попросивши супровідників цих залежностей ввести порядок за замовчуванням. Гаразд, отже, тепер вам або доведеться замінити модель, яка використовується для будь-чого, що ви робите (іноді хороша ідея, але погана для вирішення такої другорядної проблеми).

Отже, вам залишається вирішувати це на рівні перегляду. Ви також хочете зробити щось, що буде добре грати з будь-яким класом фільтра замовлення, який ви застосували. Для цього встановіть параметр подання ordering.

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

Також див. Чи існує сортування моделі Django List View?



1

У моєму випадку мені довелося додати order_by('id')замість ordering.

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

0

Натомість оновіть мета-клас моделі.

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

Ви все ще можете замінити впорядкування з атрибута подання 'упорядкування', як радив AlanSE раніше.

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

-2

В тому числі це не спрацювало для мене.

class Meta:
   ordering = ['-id']

Але змінив get_queryset (self) та відсортував список за допомогою .order_by ('id') . Можливо, це спрацювало, тому що я використовую фільтри, я не знаю

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')
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.