Manually order a Django queryset to match a predefined list
Say you have a need to manually position objects from a queryset. For example say you're ordering a list where you want an object with a certain attribute to be first, an object with a different attribute to be second, and so on.
One way to address this is to get each one and then chain them:
import itertools # Use .filter() instead of .get() to avoid a TypeError that object is not iterable obj_1 = MyModel.objects.filter(id=4) obj_2 = MyModel.objects.filter(id=2) obj_3 = MyModel.objects.filter(id=5) queryset = list(itertools.chain(obj_1, obj_2, obj_3))
But what about when you also need to maintain calling those objects as a single queryset rather than than a list. For example the
queryset for a Django
ModelForm form field.
from django.db.models import Case, When # this is the pre-defined order of MyModel objects we want to return ordered_list_of_ids = [4, 2, 5, 3, 1] # create a Case/When/then statement that says "when ID is 4 then position is 0, when ID is 2 then position is 1, and so on preserved_ordering = Case(*[When(id=id, then=position) for position, id in enumerate(ordered_list_of_ids)]) queryset = MyModel.objects.filter(id__in=ordered_list_of_ids).order_by(preserved_ordering)
Email us at email@example.com.
Found this useful?
We always appreciate a pint!