Django ORMのfilter入門
条件に一致するデータを複数取得
Django ORMのfilter()メソッドを使って、条件に一致する複数のデータを取得する方法とフィールドルックアップを解説します。
こんな人向けの記事です
- Django ORMで条件付き検索を行いたい人
- フィールドルックアップの種類を知りたい人
- AND/OR条件の使い方を学びたい人
Step 1filter()メソッドの基本
Django ORMで条件に一致する複数のデータを取得するには、filter()メソッドを使います。filter()はQuerySetを返すため、0件以上の結果を安全に扱えます。
Python
# models.py
from django.db import models
class Employee(models.Model):
name = models.CharField(max_length=100)
department = models.CharField(max_length=50)
age = models.IntegerField()
salary = models.IntegerField()
is_active = models.BooleanField(default=True)
def __str__(self):
return self.namePython
# 部署が"営業部"の社員を全件取得
employees = Employee.objects.filter(department="営業部")
for emp in employees:
print(f"{emp.name} - {emp.department}")
# 結果の件数を確認
print(f"該当: {employees.count()}件")実行結果
田中太郎 - 営業部
佐藤花子 - 営業部
該当: 2件filter()は条件に一致するデータがない場合も例外を発生させず、空のQuerySetを返します。これがget()との大きな違いです。
Step 2フィールドルックアップ
Django ORMでは、フィールド名の後に__(ダブルアンダースコア)を付けることで、様々な条件を指定できます。
Python
# === 比較演算 ===
# 完全一致(デフォルト)
Employee.objects.filter(age=30)
Employee.objects.filter(age__exact=30) # 同じ意味
# 大なり / 小なり
Employee.objects.filter(age__gt=30) # 30より大きい(>)
Employee.objects.filter(age__gte=30) # 30以上(>=)
Employee.objects.filter(age__lt=30) # 30未満(<)
Employee.objects.filter(age__lte=30) # 30以下(<=)
# === 文字列検索 ===
# 部分一致
Employee.objects.filter(name__contains="田中") # 大文字小文字を区別
Employee.objects.filter(name__icontains="tanaka") # 大文字小文字を無視
# 前方一致 / 後方一致
Employee.objects.filter(name__startswith="田")
Employee.objects.filter(name__endswith="郎")
# === 範囲・リスト ===
# 範囲指定
Employee.objects.filter(age__range=(25, 35)) # 25以上35以下
# リスト内の値
Employee.objects.filter(department__in=["営業部", "開発部"])
# NULLチェック
Employee.objects.filter(department__isnull=True)フィールドルックアップの命名規則
フィールドルックアップはフィールド名__ルックアップ名の形式で指定します。iが先頭に付くものは大文字小文字を無視(case-insensitive)する版です。例: contains → icontainsStep 3AND条件とOR条件
filter()に複数の条件を渡すとAND条件になります。OR条件にはQオブジェクトを使います。
Python
from django.db.models import Q
# AND条件: filter()にキーワード引数を複数渡す
employees = Employee.objects.filter(department="営業部", age__gte=30)
# AND条件: filter()をチェーンする(同じ結果)
employees = Employee.objects.filter(department="営業部").filter(age__gte=30)
# OR条件: Qオブジェクトを使う
employees = Employee.objects.filter(
Q(department="営業部") | Q(department="開発部")
)
# AND + OR の組み合わせ
employees = Employee.objects.filter(
Q(department="営業部") | Q(department="開発部"),
age__gte=25 # これはAND条件として追加される
)
# NOT条件: ~演算子
employees = Employee.objects.filter(~Q(department="営業部"))
# 複雑な条件の組み合わせ
employees = Employee.objects.filter(
(Q(department="営業部") & Q(age__gte=30)) |
(Q(department="開発部") & Q(salary__gte=500000))
)Step 4exclude()で除外する
exclude()はfilter()の逆で、条件に一致するデータを除外します。
Python
# 営業部以外の社員を取得
employees = Employee.objects.exclude(department="営業部")
# filter()とexclude()の組み合わせ
# 開発部の社員で、非アクティブな人を除外
employees = Employee.objects.filter(
department="開発部"
).exclude(
is_active=False
)
# 上記と同じ意味
employees = Employee.objects.filter(
department="開発部",
is_active=True
)実行結果
<QuerySet [<Employee: 鈴木一郎>, <Employee: 山田次郎>]>Step 5実践的なフィルタリング
ビューでの検索機能の実装例を紹介します。
Python
# views.py
from django.shortcuts import render
from django.db.models import Q
from .models import Employee
def employee_search(request):
queryset = Employee.objects.filter(is_active=True)
# キーワード検索
keyword = request.GET.get("q", "")
if keyword:
queryset = queryset.filter(
Q(name__icontains=keyword) |
Q(department__icontains=keyword)
)
# 部署フィルタ
dept = request.GET.get("department", "")
if dept:
queryset = queryset.filter(department=dept)
# 年齢範囲フィルタ
min_age = request.GET.get("min_age")
max_age = request.GET.get("max_age")
if min_age:
queryset = queryset.filter(age__gte=int(min_age))
if max_age:
queryset = queryset.filter(age__lte=int(max_age))
context = {
"employees": queryset,
"count": queryset.count(),
"keyword": keyword,
}
return render(request, "employee/list.html", context)QuerySetは遅延評価
filter()やexclude()を呼んだ時点ではSQLは実行されません。実際にデータにアクセスしたとき(ループ、list()、len()など)に初めてSQLが発行されます。この仕組みにより、複数のfilter()をチェーンしても効率的にクエリが組み立てられます。まとめ
filter()は条件に一致するデータをQuerySetで複数件返す- フィールドルックアップ(
__gt,__contains等)で柔軟な条件指定ができる - AND条件はfilter()の引数またはチェーンで、OR条件はQオブジェクトで指定
exclude()で条件に一致するデータを除外できる- QuerySetは遅延評価されるため、チェーンしても効率的