【问题标题】:Python Django Rest Framework UnorderedObjectListWarningPython Django Rest 框架 UnorderedObjectListWarning
【发布时间】:2017-10-17 10:28:45
【问题描述】:

我从 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)

我已经追溯到 Django Pagination 模块: https://github.com/django/django/blob/master/django/core/paginator.py#L100

好像和我的查询集代码有关:

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

如何找到有关此警告的更多详细信息?似乎我需要在每个过滤器的末尾添加一个order_by(id),但我似乎无法找到需要添加 order_by 的代码(因为警告不返回堆栈跟踪,所以它随机发生在我的试运行期间)。

谢谢!

编辑:

所以通过使用@KlausD。详细提示,我查看了导致此错误的测试:

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

这转到OrderViewSet,但 get_queryset 中的任何东西都不会导致它,并且序列化程序类中的任何东西都不会导致它。我有其他测试使用相同的代码来获取 /api/orders 并且不会导致它.... DRF 在 get_queryset 之后做什么?

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

如果我将回溯放到分页中,那么我会得到一大堆与 django rest 框架相关的东西,但没有任何东西可以指出我的哪个查询触发了订单警告。

【问题讨论】:

  • 通常应该很容易通过导致警告的测试名称找到。您可能希望以冗长的方式运行测试(大多数测试运行程序为-v 2
  • 感谢@KlausD。这是一个有用的提醒。
  • 查找您正在执行offsetlimit 但没有order_by 的查询
  • 谢谢@gipsy。这些我都没有……

标签: python django django-rest-framework


【解决方案1】:

所以为了解决这个问题,我必须找到所有的 alloffsetfilterlimit 子句,并为它们添加一个 order_by 子句。我通过添加默认排序修复了一些:

class Meta:
   ordering = ['-id']

在 Django Rest Framework (app/apiviews.py) 的 ViewSets 中,我不得不更新所有 get_queryset 方法,因为添加默认排序似乎不起作用。

希望这对其他人有所帮助。 :)

【讨论】:

  • 太棒了,不知道DRF也读取模型来订购
  • 我的模型中确实有默认排序,但我仍然收到此警告:|
  • 我的错误。我在父类中进行了排序,但是我在没有properly subclassing it as described in the docs 的情况下覆盖了 Meta 属性,而在子类的 Meta 中我没有排序,因此父类的值丢失了。
  • 注意ordering = ['-id'] 中添加- 按降序排列您的查询。
  • 我认为正确的解决方案实际上是在模型上指定默认排序,因为这可能会在将来对碰巧使用此模型的任何其他事物产生严重的副作用.可能会再次困扰您的副作用的一个示例是查询规划器决定使用不正确的索引来优先排序而不是过滤。这会对较大的表产生巨大的性能影响。相反,您应该在您的 drf 视图上指定默认排序,或者特别是在作者的情况下,您返回的查询应该指定 order_by()
【解决方案2】:

当我在 view.py 中使用 objects.all() 时收到此警告

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

为了解决这个问题,我将代码更改为:

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

【讨论】:

  • 我认为应该是Profile.objects.all().order_by('id') .. 至少这对我有用,否则我会得到AttributeError: type object 'Profile' has no attribute 'get_queryset'
【解决方案3】:

就我而言,我必须添加 order_by('id') 而不是 ordering

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

Ordering 需要在模型中使用 Class Meta(不是 View)。

【讨论】:

    【解决方案4】:

    让我给出一个关于新发展的最新答案......

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

    User 模型的默认排序已在 Django 中删除。如果您因为升级而出现在此页面,则很可能与此更改有关。

    您可能正在处理这个问题的 2 个版本。

    1. 您自己的模型在其Meta 中没有默认排序(请参阅已接受的答案)
    2. 您正在使用应用程序中的模型作为没有默认排序的依赖项

    从字面上看,Django User 模型本身不遵守排序,很明显第二种情况无法通过要求这些依赖项的维护者输入默认排序来解决。好的,所以现在您要么必须覆盖正在使用的模型,无论您做什么(有时是个好主意,但不适合解决这样一个小问题)。

    因此,您只能在视图级别解决它。您还想做一些可以很好地与您应用的任何排序过滤器类一起使用的东西。为此,设置视图的ordering 参数。

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

    另见Is there Django List View model sort?

    【讨论】:

      【解决方案5】:

      【讨论】:

        【解决方案6】:

        包括这个对我不起作用。

        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')
        

        【讨论】:

          【解决方案7】:

          改为更新模型元类。

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

          您仍然可以根据 AlanSE 之前的建议从视图属性“ordering”覆盖排序。

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

          【讨论】:

            【解决方案8】:

            在我的例子中,它需要一个元组,并且即使您只解析其中的一个项目,该元组也必须包含一个逗号。

                 class Meta:
                  ordering = ('-name',)
            

            【讨论】:

              猜你喜欢
              • 2018-09-20
              • 1970-01-01
              • 2016-08-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-10-19
              • 2017-11-09
              相关资源
              最近更新 更多