Is it possible to sort a django queryset by the list of elements provided in the query? For example, if I do
m.objects.filter(id__in=[3,1,8])
I wan't the order of the queryset to be the element of id 3, the element of id 1 and the element of id 8.
Thanks
Since there exists Case
and When
in Django >= 1.11 you can do it in a more orm-like way keeping all the benefits of your queryset:
from django.db import models
order = ['b', 'a', 'z', 'x', 'c']
_whens = []
for sort_index, value in enumerate(order):
_whens.append(
models.When(my_field=value, then=sort_index)
)
qs = MyModel.objects.annotate(
_sort_index=models.Case(
*_whens,
output_field=models.IntegerField()
)
)
qs.order_by('_sort_index')
This will generate something like this:
from django.db import models
order = ['b', 'a', 'z', 'x', 'c']
qs = MyModel.objects.annotate(
_sort_index=models.Case(
models.When(my_field='b', then=0),
models.When(my_field='a', then=1),
models.When(my_field='z', then=2),
models.When(my_field='x', then=3),
models.When(my_field='c', then=4),
output_field=models.IntegerField()
)
).order_by('_sort_index')
I would suggest to use this only with a small amount of list-items because it blows up the database-query.
https://docs.djangoproject.com/ko/1.11/ref/models/conditional-expressions/#case
No. There is no way to do what you want short of some contrived mechanism like:
qs = m.objects.filter(id__in=[3,1,8])
qs_sorted = list()
for id in [3,1,8]:
qs_sorted.append(qs.get(id=id))
You'd need to throw some exception handling in there as well, just in case one of the specified ids wasn't actually returned.
The negatives are that this will effectively negate the lazy loading of queryset. In fact, it's very likely to generate multiple DB queries (haven't tested that though). Also, you end up with a normal python list instead of a queryset, so no more filtering is possible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With