djangoのquerysetを任意の順番でsortする

djnagoではorder_by('hoge')とするとhogeの昇順でならんでいくことは当たり前のように知っているよね。

が、ぼくがやりたかったのは、任意の値でのソート。
databaseに定義されてない値でソートしたかったのです。

とても参考になったstack overflowはこちら。
Django order_by specific order - Stack Overflow

ただしdjango >= 1.8です

TL;DR

from djnago.db.models import Case, When, Value, FloatField

# { pid: specific_value, }
specific_values = {
  '1': 100.0,
  '2': 50.0,
  '3': 25.0,
  '4': 123.4,
  '5': 599.33,
}

# sqlのCASE式にしたい条件のリスト
cases = []

# casesにCASE式にしたい条件をつめていく
for pid, specific_value in specific_values.items():
    cases.append(When(id=pid, then=Value(specific_value)))

# Hogeモデルに対して、pidで絞り込んだあとにcasesをつかってspecific_valueについて注釈づけてorder_byする
Hoge.objects.filter(id__in=specific_values.keys()).annotate(specific_value=Case(
    *cases,
    output_field=FloatField()
)).order_by(specific_value)

詳しい説明

Conditional Expressions | Django documentation | Django

TIPS

  • casesに条件をつめこむため、Caseインスタンスを作成する際に、*で展開してあげないといけない。

ここだけ気をつければ非常に便利(使い所があまりないのが玉に瑕)。