Django以特定顺序从id数组中获取QuerySet

inheritance人为你一个快速的:

我有我想用来返回一个QuerySet(或数组,如果需要的话)的ID列表,但我想保持该顺序。

谢谢

我不认为你可以在数据库级别执行这个特定的顺序,所以你需要在python中执行。

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] 

这就build立了一个以id为键的对象字典,所以在构buildsorting列表时可以很容易地检索它们。

从Django 1.8开始,你可以这样做:

 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) 

如果你想使用in_bulk来做到这一点,你实际上需要合并上面的两个答案:

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

否则,结果将是一个字典,而不是一个特定的有序列表。

以下是在数据库级别执行此操作的一种方法。 复制粘贴: blog.mathieu-leplatre.info :

MySQL

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

和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; 

和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',)) 
 id_list = [1, 5, 7] objects = Foo.objects.filter(id__in=id_list) sorted(objects, key=lambda i: id_list.index(i.pk))