2

I have a generic list view from which I paginate using the querysets from two separate models : Message and safeTransaction.

django terminal output gives this warning upon entry to my inbox view :

/usr/local/lib/python3.6/dist-packages/django/views/generic/list.py:88: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: QuerySet. allow_empty_first_page=allow_empty_first_page, **kwargs)

This is the View and get_context_data method :

### Inbox list class
class InboxListView(ListView):

#This view lets the user view all the messages created in a list

model = Message
template_name = "myInbox/inbox.html"
paginate_by = 3 # paginating twice here 
#so the page gets paginated in a convenient way for my template.

def get_context_data(self, **kwargs):
    message_list = Message.objects.filter(recipient=self.request.user)
    .order_by('-date')
    safeTransaction_list = SafeTransaction.objects
        .filter(trans_recipient=self.request.user)
        .order_by('-date') 
    queryset = list(chain(message_list, safeTransaction_list))
    #paginator setup start
    paginator = Paginator(queryset,3)
    page = self.request.GET.get('page')
    safe_T_list = paginator.get_page(page) #iterable list for template
    #paginator setup done
    context = super(InboxListView, self).get_context_data(**kwargs)
    context.update({
        'now': timezone.now(),
        'message_list':safe_T_list,
    })
    return context

What I am doing in this method is chaining the filtered querysets into a list, then paginating that as one queryset. The problem is that even before I do that, my filtered Messages and SafeTransactions are seen as unordered lists. This confuses me because the typical usage of order_by() on the django website is similar to what I have done.

In summary, I want to paginate using a queryset built from different object bases, but my filtered objects are consider unordered for reasons I don't understand.

stack trace :

Starting development server at http://127.0.0.1:4200/
Quit the server with CONTROL-C.
[17/Dec/2018 07:52:52] "GET / HTTP/1.1" 200 1490
[17/Dec/2018 07:52:52] "GET /static/css/mystyle.css HTTP/1.1" 200 1555
[17/Dec/2018 07:52:52] "GET /static/css/w3pro.css HTTP/1.1" 200 15672
[17/Dec/2018 07:52:52] "GET /static/css/w3.css HTTP/1.1" 200 23293
[17/Dec/2018 07:52:52] "GET /static/favicon.ico HTTP/1.1" 200 8192
/usr/local/lib/python3.6/dist-packages/django/views/generic/list.py:88: UnorderedObjectListWarning: Pagination may yield inconsistent results with             an unordered object_list: <class 'account.models.Message'> QuerySet.
  allow_empty_first_page=allow_empty_first_page, **kwargs)
[17/Dec/2018 07:52:58] "GET /inbox HTTP/1.1" 200 3134
[17/Dec/2018 07:52:58] "GET /static/css/mystyle.css HTTP/1.1" 200 1555
timi95
  • 368
  • 6
  • 23
  • 1
    Please show the full traceback. Which paginator is this error coming from? The error you have posted implies it's coming from the one built into the view, not the one you show here. And which version of Django are you using? – Daniel Roseman Dec 15 '18 at 19:17
  • 1
    Using a list like you did here `queryset = list(chain(message_list, safeTransaction_list))` in `Paginator` is always going to trigger this warning. This part of code in the Paginator `getattr(self.object_list, 'ordered', None)` will not validate with list. – Borut Dec 15 '18 at 22:55
  • @DanielRoseman Django version 2.1 I will put up the full stack trace in a minute, thanks. – timi95 Dec 17 '18 at 06:44
  • 1
    @Borut that's not true. Paginators explicitly do work with lists, and that code checks that *if it is a queryset*, `ordered` must be true; if it doesn't have one, it isn't a queryset so the check is bypassed. Something else is going on in OP's code. – Daniel Roseman Dec 17 '18 at 07:11
  • @DanielRoseman I have added the full terminal output in my recent edit. though I don't think it says much. Is there a more convenient way of pagination you know off to use on separate querysets coming from different model bases ? – timi95 Dec 17 '18 at 07:58

1 Answers1

0

I know this is late but if anyone encounters this warning going forward. You need to understand that the UnorderedObjectListWarning is simply calling your attention to note that each call to your QuerySet will not return the same results because the object list is not ordered.

So to get rid of this warning, you simply need to order your object list properly with a valid DateTimeField field defined on your model such as created_at or updated_at like I have below on the sample model, or you can also define an OrderingFilter if you're using DRF. You can check out this Stackoverflow answer if you're interested in that.

If I have a model like this:

from django.db import models

class InboxList(models.Model):
    user = models.ForeignKey(User, related_name='user_list', on_delete=models.CASCADE)
    url = models.CharField(max_length=1000)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

I can easily filter by user (you can filter with any of your model field) and order the object list by created_at or updated_at as defined on my InboxList model above. So overriding get_queryset(), the fix will be:

def get_queryset(self):
return InboxList.objects.filter(user=self.request.user).order_by("-created_at")

Basically, the solution is to order the object list with a valid DateTimeField field defined on your model.