Python Django Rest Framework UnorderedObjectListWarning

83

Actualicé de Django 1.10.4 a 1.11.1 y, de repente, recibo muchos de estos mensajes cuando ejecuto mis pruebas:

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)

Lo rastreé hasta el módulo de paginación de Django: https://github.com/django/django/blob/master/django/core/paginator.py#L100

Parece estar relacionado con mi código de conjunto de consultas:

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

¿Cómo puedo encontrar más detalles sobre esta advertencia? Parece ser que necesito agregar un order_by(id)al final de cada filtro, pero parece que no puedo encontrar qué código necesita el order_by agregado (porque la advertencia no devuelve un seguimiento de pila y, por lo tanto, sucede aleatoriamente durante mi prueba correr).

¡Gracias!

Editar:

Entonces, usando @KlausD. consejo de verbosidad, miré una prueba que causaba este error:

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

Esto va a OrderViewSetpero ninguna de las cosas en get_queryset lo causa y nada en la clase de serializador lo causa. Tengo otras pruebas que usan el mismo código para obtener / api / orders y esas no lo causan ... ¿Qué hace DRF después de get_queryset?

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

Si pongo un rastreo en la paginación, obtengo un montón de cosas relacionadas con el marco de descanso de django, pero nada que indique cuál de mis consultas está activando la advertencia de orden.

Denise Mauldin
fuente
1
Por lo general, debería ser fácil de encontrar por el nombre de la prueba que causa la advertencia. Es posible que desee ejecutar pruebas con verbosidad ( -v 2en la mayoría de los corredores de pruebas)
Klaus D.
Gracias @KlausD. ese es un recordatorio útil.
Denise Mauldin
1
Busca consultas en las que estás haciendo un offsety limitpero noorder_by
gipsy
Gracias @gipsy. No tengo ninguno de esos ....
Denise Mauldin

Respuestas:

131

Así que con el fin de solucionar este problema tenía que encontrar todos los all, offset, filter, y limitlas cláusulas y añadir una order_bycláusula a ellos. Algunos los arreglé agregando un pedido predeterminado:

class Meta:
   ordering = ['-id']

En ViewSets for Django Rest Framework (app / apiviews.py) tuve que actualizar todos los get_querysetmétodos ya que agregar un orden predeterminado no parecía funcionar.

Espero que esto ayude a alguien más. :)

Denise Mauldin
fuente
2
Impresionante, no sabía que DRF también lee el modelo para realizar pedidos <3
Amir Savand
Tengo un pedido predeterminado en mi modelo, pero sigo recibiendo esta advertencia: |
Ariel
Mi error. Tenía pedidos en la clase principal, pero estaba anulando el atributo Meta sin subclasificarlo correctamente como se describe en los documentos , y en la clase secundaria 'Meta no tenía pedidos, por lo que se perdió el valor del padre.
Ariel
1
Nota que la adición de la -de ordering = ['-id']las órdenes de su consulta en orden descendente.
Elrond apoya a Monica el
49

Recibí esta advertencia cuando usé objects.all () en mi view.py

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

para arreglar esto cambié mi código a:

profile_list = Profile.objects.get_queryset().order_by('id')
paginator = Paginator(profile_list, 25)
Rajiv Sharma
fuente
1
Creo que debería ser Profile.objects.all().order_by('id')... al menos eso funciona para mí, de lo contrario lo consigoAttributeError: type object 'Profile' has no attribute 'get_queryset'
radtek
8

Déjame darte una respuesta actualizada a los nuevos desarrollos ...

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

El orden predeterminado del Usermodelo se ha eliminado en Django. Si se encontró en esta página debido a una actualización, es muy probable que esté relacionado con este cambio.

Hay 2 versiones de este problema con las que podría estar lidiando.

  1. su propio modelo no tiene un orden predeterminado en su Meta(ver respuesta aceptada)
  2. está utilizando un modelo de una aplicación que está utilizando como una dependencia que no tiene un orden predeterminado

Dado que, literalmente, el Usermodelo de Django en sí mismo no se adhiere al orden, está muy claro que el segundo escenario no se puede resolver pidiendo a los mantenedores de esas dependencias que pongan un orden predeterminado. Bien, ahora tiene que anular el modelo que se está utilizando para lo que sea que esté haciendo (a veces es una buena idea, pero no es buena para abordar un problema tan pequeño).

Así que te queda abordarlo en el nivel de vista. También desea hacer algo que funcione bien con cualquier clase de filtro de pedido que haya aplicado. Para eso, configure el orderingparámetro de la vista .

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

Consulte también ¿Hay ordenación del modelo de vista de lista de Django?

AlanSE
fuente
0

En su lugar, actualice la metaclase del modelo.

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

aún puede anular el orden desde el atributo de vista 'ordenar' como lo aconsejó AlanSE anteriormente.

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

En mi caso, tuve que agregar en order_by('id')lugar de ordering.

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

Incluir esto no funcionó para mí.

class Meta:
   ordering = ['-id']

Pero cambiar get_queryset (self) y ordenar la lista con .order_by ('id') sí lo hizo. Tal vez funcionó porque estoy usando filtros, no lo sé

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
fuente