Question

I fetch the latest 5 rows from a Foo model which is ordered by a datetime field.

qs = Foo.objects.all()[:5]

In the following step, I want to reorder the queryset by some other criteria (actually, by the same datetime field in the opposite direction). But reordering after a slice is not permitted. reverse() undoes the first ordering, giving me a differet queryset. Is there a way to accomplish what I want without creating a list from the queryset and doing the ordering using it?

Was it helpful?

Solution

No, there's no way of doing that. order_by is an operation on the database, but when you slice a queryset it is evaluated and doesn't go back to the database after that.

Sounds like you already know the solution, though: run reversed() on the evaluated qs.

qs = reversed(Foo.objects.all()[:5])

OTHER TIPS

order_by gives you SQL in-database ordering. You're already using that, and then slicing on it. At that point, the results are retrieved into memory. If you want to change their order, you need to use Python in-memory sorting to do it, not the ORM in-database sorting.

In your case, Daniel has already given the best solution: since you simply want to sort by the same field, but in the other order, just reverse the list you have:

qs = Foo.objects.all()[:5]
objs = reversed(qs)

If you had wanted to sort by some other field, then you'd use the sorted() function with a custom key function:

qs = Foo.objects.all()[:5]
objs = sorted(qs, key=lambda o: o.some_other_field)

Late answer, but this just worked for me:

import random
sorted(queryset[:10], key=lambda x: random.random())
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top