Djangoは特定の順序でIDの配列からQuerySetを取得します


83

ここにあなたのための簡単なものがあります:

QuerySet(または必要に応じて配列)を返すために使用するIDのリストがありますが、その順序を維持したいと思います。

ありがとう

回答:


73

データベースレベルでその特定の順序を強制できるとは思わないので、代わりに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]

これにより、IDをキーとしてオブジェクトのディクショナリが構築されるため、ソートされたリストを構築するときにオブジェクトを簡単に取得できます。


私はこれが当てはまらないことを望んでいました:(クリーンなコードに感謝します!
neolaser 2011

3
これを行うときは結果をメモリに保存するので、巨大なクエリに注意してください。
JJ。

12
自分で辞書を作成するのではなく、querysets in_bulk()メソッドを使用するのではないでしょうか。
マットオースティン

これに伴う問題は、id_list内のオブジェクトが存在しない場合、エラーをスローすることです。
madprops 2016

dictの理解を使用してみませんか?
wieczorek1990 2016

180

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)

15
実際に
クエリセットを

1
私はまだdjangoCase Whenが過小評価されていると思います!
バブ2017年

distinct()order_by case when句を使用しますが、エラーが発生しました。どんなサポートもお願いします。
elquimista 2017年

SELECT DISTINCT ON expressions must match initial ORDER BY expressions-ここにエラーメッセージがあります
elquimista 2017年

これがベストアンサーであることを強くお勧めします!
トニー

28

in_bulkを使用してこれを実行する場合は、実際には上記の2つの回答をマージする必要があります。

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

それ以外の場合、結果は特別に順序付けられたリストではなく辞書になります。


1
これは良い答えではありません。
トニー

25

これをデータベースレベルで行う方法は次のとおりです。コピー&ペースト: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',))

ワオ。それは激しいです。ありがとう!
ダン・ゲイル

この答えをありがとう。
Subangkar KrS

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

1
これがどのように機能し、なぜOPの問題を解決するのかを説明するテキストを追加してください。他の人が理解するのを助けます。
APC

ベストアンサー。ありがとう!
webjunkie 2016

うまく機能しますが、追加情報を使用できます
xtrinch 2016年

これは、順序付けられたidlistに対してのみ機能します。それがどのシーケンスでも機能するかどうかを確認できますか...私には当てはまらないようです。
Doogle 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.