Django get a QuerySet from array of id's in specific order

DjangoArrays

Django Problem Overview


heres a quick one for you:

I have a list of id's which I want to use to return a QuerySet(or array if need be), but I want to maintain that order.

Thanks

Django Solutions


Solution 1 - Django

Since Django 1.8, you can do:

from django.db.models import Case, When

pk_list = [10, 2, 1]
preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(pk_list)])
queryset = MyModel.objects.filter(pk__in=pk_list).order_by(preserved)

Solution 2 - Django

I don't think you can enforce that particular order on the database level, so you need to do it in python instead.

id_list = [1, 5, 7]
objects = Foo.objects.filter(id__in=id_list)

objects = dict([(obj.id, obj) for obj in objects])
sorted_objects = [objects[id] for id in id_list]

This builds up a dictionary of the objects with their id as key, so they can be retrieved easily when building up the sorted list.

Solution 3 - Django

If you want to do this using in_bulk, you actually need to merge the two answers above:

id_list = [1, 5, 7]
objects = Foo.objects.in_bulk(id_list)
sorted_objects = [objects[id] for id in id_list]

Otherwise the result will be a dictionary rather than a specifically ordered list.

Solution 4 - Django

Here's a way to do it at database level. Copy paste from: blog.mathieu-leplatre.info :

MySQL:

SELECT *
FROM theme
ORDER BY FIELD(`id`, 10, 2, 1);

Same with Django:

pk_list = [10, 2, 1]
ordering = 'FIELD(`id`, %s)' % ','.join(str(id) for id in pk_list)
queryset = Theme.objects.filter(pk__in=[pk_list]).extra(
           select={'ordering': ordering}, order_by=('ordering',))

PostgreSQL:

SELECT *
FROM theme
ORDER BY
  CASE
    WHEN id=10 THEN 0
    WHEN id=2 THEN 1
    WHEN id=1 THEN 2
  END;

Same with Django:

pk_list = [10, 2, 1]
clauses = ' '.join(['WHEN id=%s THEN %s' % (pk, i) for i, pk in enumerate(pk_list)])
ordering = 'CASE %s END' % clauses
queryset = Theme.objects.filter(pk__in=pk_list).extra(
           select={'ordering': ordering}, order_by=('ordering',))

Solution 5 - Django

id_list = [1, 5, 7]
objects = Foo.objects.filter(id__in=id_list)
sorted(objects, key=lambda i: id_list.index(i.pk))

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionneolaserView Question on Stackoverflow
Solution 1 - DjangoSoitjeView Answer on Stackoverflow
Solution 2 - DjangoReiner GereckeView Answer on Stackoverflow
Solution 3 - DjangoRick WesteraView Answer on Stackoverflow
Solution 4 - DjangouserView Answer on Stackoverflow
Solution 5 - DjangoAndrew GView Answer on Stackoverflow