Django ORMのorder_by入門
データを昇順・降順に並び替える
Django ORMのorder_by()メソッドを使って、データを昇順・降順に並び替える方法を解説します。
こんな人向けの記事です
- Django ORMでデータの並び替え方法を学びたい人
- 複数フィールドでの並び替えを知りたい人
- ランダム順やNULL値の扱いを理解したい人
Step 1order_by()の基本
QuerySetのorder_by()メソッドでデータの並び順を指定します。フィールド名の前に-を付けると降順になります。
Python
# models.py
from django.db import models
class Employee(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
salary = models.IntegerField()
hired_date = models.DateField()
department = models.CharField(max_length=50)
def __str__(self):
return self.namePython
# 昇順(小さい順): フィールド名をそのまま指定
employees = Employee.objects.order_by("age")
for emp in employees:
print(f"{emp.name}: {emp.age}歳")
print("---")
# 降順(大きい順): フィールド名の前に - を付ける
employees = Employee.objects.order_by("-salary")
for emp in employees:
print(f"{emp.name}: {emp.salary}円")実行結果
佐藤花子: 25歳
鈴木一郎: 30歳
田中太郎: 35歳
---
田中太郎: 600000円
鈴木一郎: 450000円
佐藤花子: 350000円Step 2複数フィールドでの並び替え
複数のフィールドを指定すると、第1キー、第2キーの順で並び替えられます。
Python
# 部署で昇順 → 同じ部署内では年齢で降順
employees = Employee.objects.order_by("department", "-age")
for emp in employees:
print(f"{emp.department} | {emp.name}: {emp.age}歳")
# filter()と組み合わせる
employees = Employee.objects.filter(
department="開発部"
).order_by("-salary")
# order_by()をチェーンすると、後の指定が優先される
employees = Employee.objects.order_by("name").order_by("age")
# → ageで並び替えられる(nameの指定は上書きされる)実行結果
営業部 | 田中太郎: 35歳
営業部 | 佐藤花子: 25歳
開発部 | 鈴木一郎: 30歳
開発部 | 山田次郎: 28歳order_by()のチェーンに注意
order_by()を複数回チェーンすると、最後に指定した並び順だけが有効になります。複数フィールドで並び替えたい場合は、1回のorder_by()に複数の引数を渡してください。Step 3Metaクラスでデフォルト順を指定
モデルのMetaクラスでorderingを指定すると、order_by()を呼ばなくても常にその順序で取得されます。
Python
# models.py
class Employee(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
hired_date = models.DateField()
class Meta:
ordering = ["-hired_date"] # 入社日の降順がデフォルト
def __str__(self):
return self.namePython
# orderingが指定されているため、自動的に入社日降順で取得
employees = Employee.objects.all()
# デフォルトの並び順を解除したい場合
employees = Employee.objects.order_by() # 引数なしで並び順リセット
# デフォルトの並び順を別の順に上書き
employees = Employee.objects.order_by("name")orderingの影響
Meta.orderingを指定すると全てのクエリにORDER BY句が追加されます。パフォーマンスに影響する場合があるので、必要なときだけorder_by()で指定するという設計も検討しましょう。Step 4ランダム順とNULL値の制御
Python
from django.db.models import F
# ランダムな順序で取得
employees = Employee.objects.order_by("?")
# ランダムに1件取得
random_employee = Employee.objects.order_by("?").first()
print(f"ランダム: {random_employee.name}")
# NULLの並び順を制御(Django 4.0以降)
from django.db.models.functions import Coalesce
from django.db.models import Value
# NULL値を最後にする
employees = Employee.objects.order_by(
F("hired_date").asc(nulls_last=True)
)
# NULL値を最初にする
employees = Employee.objects.order_by(
F("hired_date").desc(nulls_first=True)
)ランダム順のパフォーマンス
order_by("?")はデータベースのORDER BY RANDOM()に変換されます。データ件数が多い場合はパフォーマンスが低下するため、大量データでのランダム取得にはIDを使った別の方法を検討してください。Step 5実践的な並び替え
Python
from django.db.models import Count, Avg
# 関連モデルのフィールドで並び替え(JOINが発行される)
# employees = Employee.objects.order_by("department__name")
# アノテーションを使った並び替え
# 部署ごとの社員数で並び替え
from django.db.models import Count
departments = Employee.objects.values("department").annotate(
emp_count=Count("id")
).order_by("-emp_count")
for dept in departments:
print(f"{dept['department']}: {dept['emp_count']}人")
# 条件付きの並び替え(Case/When)
from django.db.models import Case, When, IntegerField
priority_order = Employee.objects.annotate(
dept_priority=Case(
When(department="役員", then=0),
When(department="管理部", then=1),
When(department="開発部", then=2),
default=3,
output_field=IntegerField(),
)
).order_by("dept_priority", "name")
# ビューでのソート切り替え
def employee_list(request):
sort = request.GET.get("sort", "name")
direction = request.GET.get("dir", "asc")
valid_sorts = ["name", "age", "salary", "hired_date"]
if sort not in valid_sorts:
sort = "name"
order_field = f"-{sort}" if direction == "desc" else sort
employees = Employee.objects.order_by(order_field)
return render(request, "employee/list.html", {
"employees": employees,
"current_sort": sort,
"current_dir": direction,
})まとめ
order_by("field")で昇順、order_by("-field")で降順に並び替え- 複数フィールドは
order_by("field1", "-field2")のように1回で指定する - Meta.orderingでデフォルトの並び順を設定できる
order_by("?")でランダム順、nulls_last=TrueでNULLの位置を制御- Case/Whenやアノテーションで高度な並び替えも可能