🙆
order byを使って、QuerySetを任意の順番でソートする
書くこと
- 並べ替えたい順番のid配列(pk等)を持っている状態で、QuerySetのソートする方法
- pythonで処理せず、order byで実現する
利用する技術
- Django
- MySQL
- SQlite
今日のゴール
## 前提: 以下は変数として持つ
# - queryset: 並び替えたい対象のQuerySet
# - ids: 並び順を示すpk(等)の配列
from .common import sorter
# 取得結果:
# 第一引数のquerysetを第二引数で与えたidの順番に並べ替えたもの
sorted_queryset = sorter.sort(queryset, ids)
方法論
MySQL Version
以下のクエリを発行できるように、
# example: idが[2, 3, 1]の順に並べ替える。
SELECT *
FROM table_name
ORDER BY FIELD(id, 2, 3, 1);
以下の関数を追加。
common/sorter.py
from django.db.models.query import QuerySet
def sort(query_set: QuerySet, orders: list) -> QuerySet:
# プログラムガード
if not orders:
return query_set
sort_key = __sort_key(orders)
return query_set.extra(select={"sort_key": sort_key}, order_by=("sort_key",))
def __sort_key(orders):
order_str = ",".join(str(order) for order in orders)
return f"FIELD(id, {order_str})"
付録
SQLite3 Version
以下のクエリを発行できるように、
SELECT *
FROM table_name
ORDER BY CASE
WHEN id = 2 THEN 0
WHEN id = 3 THEN 1
WHEN id = 1 THEN 2
END;
__sort_key
だけ書き換えます。
def __sort_key(orders):
case = " ".join([f"WHEN id={pk} THEN {i}" for i, pk in enumerate(orders)])
return f"CASE {case} END"
Discussion