Aurélien
Aurélien

Reputation: 1655

Ordering listview with get_queryset

Two models : Post and Author
This view displays the last Post for each Author (author is a ForeignKey)

I want to have these posts in a descending order, but it does not work. The template keeps displaying these in a ascending way.
I try this following:

views.py

class LastestListView(ListView):
    context_object_name = 'posts'
    model = models.Post
    ordering = ['-date']
    paginate_by = 10

    def get_queryset(self):
        return self.model.objects.filter(pk__in=
        Post.objects.values('author__id').annotate(
            max_id=Max('id')).values('max_id'))

or:

class LastestListView(ListView):
    context_object_name = 'posts'
    model = models.Post
    paginate_by = 10

    def get_queryset(self):
        return self.model.objects.filter(pk__in=
        Post.objects.order_by('-date').values('author__id').annotate(
            max_id=Max('id')).values('max_id'))

Solution

The ordering has to be set in the beginning of the Queryset:

class LastestListView(ListView):
    context_object_name = 'posts'
    model = models.Post
    paginate_by = 10

    def get_queryset(self):
        return self.model.objects.order_by('-date').filter(pk__in=
        Post.objects.values('author__id').annotate(
            max_id=Max('id')).values('max_id'))

Upvotes: 4

Views: 3641

Answers (1)

hynekcer
hynekcer

Reputation: 15568

It is more exact to say that the ordering should be applied to the main query, not to subquery.

I prefer the ordering after a filter, it is only a matter of opinion.

def get_queryset(self):
    qs = (
        self.model.objects
        .filter(
            pk__in=(
                Post.objects
                .values('author_id')
                .annotate(max_id=Max('id'))
                .values('max_id')
            )
        )
        .order_by('-date')
    )
    # print(str(qs.query))   # SQL check is perfect for debugging
    return qs

Maybe this more sparse style with strict indenting helps to write an easily readable code. The advantage is that you can easier comment out a method or change the order of methods by changing the order of lines. You can see also clearly if order_by is in the main query or a subquery.

Upvotes: 5

Related Questions