綴Photo の web 側に「撮影日時順/綴った日順でアルバムを作る」を足したときの、サーバ側の設計の記録を勉強のためにまとめた制作メモ。
選んだ写真を時系列で流し込むページを作れるようにしたかった。撮影日時の順か、綴った日の順か、向き(古い順/新しい順)を選んで並べる、みたいなやつ。作りながら決めないと進めなかったのは、その並びを いつ確定させるか だった。作った時点で並べて固めてしまうのか、開くたびに並べ直すのか。
保存するのは「選んだ写真」と「並べ方の規則」
保存する形は2通りに整理した。
jsonc
// 手で並べる:写真IDの並びがそのまま答え
{ "template": "letter", "photoIds": ["3", "1", "2"] }
// 撮影日時順/綴った日順:選んだ写真 + 並べ方の規則
{
"template": "scrollstory",
"source": "timeline",
"photoIds": ["3", "1", "2"],
"rule": { "order": "taken_at", "direction": "asc" }
}枚数の上限(limit)は持たせていません。ページに入る枚数 = 渡された写真の枚数。画面側で先に「何枚にしますか」と聞かない形にしたので、サーバ側にも上限が要らなくなった。
並びは表示するたびに決める
並びの確定はサーバ側でやります。
「綴った日順」の"綴った日"はどの日か
決めないと進めない判断がもう一つあった。「綴った日順」で並べるとき、ひとつの写真に綴りが複数あったら(後から書き直したら)、どの日付で並べるのか。
決めたのは「最初に綴った日」。書き直しても並ぶ位置は動かない=最初に言葉にした順の年代記になります。
これをサーバ側のクエリに落としてもらうと、こうなった。
python
# 並べ替えキー = 最初に綴った日(id が最小の Meaning の created_at)
first_written = Meaning.objects.filter(
photo=OuterRef("pk"), owner=owner
).order_by("id").values("created_at")[:1] # いま並べ替え中の写真の“最初の綴り”を1個だけ引く
qs = qs.annotate(_sort_key=Subquery(first_written))
# …この _sort_key で並べる(direction で昇順/降順を切り替え)画面に何個の言葉を出すかとは別の判断で、そこは切り分けて持っておくことにした。
おわりに
綴Photo は写真も綴りも後から増えていく前提なので、固めない方が素直だった。
この記事は2026年6月時点の自分の理解で書いています。仕様や認識が変わってる可能性があります。