ORM

Django ORMのfilter入門|条件に一致するデータを複数取得する方法

Django ORM

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.name
Python
# 部署が"営業部"の社員を全件取得
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)する版です。例: containsicontains

Step 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は遅延評価されるため、チェーンしても効率的