🙆‍♀️

# 3.4 フィルタリングと検索の実装パターン(Django REST Framework 編)

に公開

前回の記事ではエラーハンドリングについてまとめた。
今回は業務システムで必ず必要になる フィルタリングと検索 を取り上げる。

一覧 API に「検索条件をつけたい」「大量データをページングしたい」というニーズは多く、
Django REST Framework(DRF)ではそれをシンプルに実現できる。


1. django-filter を使った検索

まずは定番の django-filter を利用する方法。

セットアップ

pip install django-filter

設定に追加:

# settings.py
REST_FRAMEWORK = {
    "DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"],
}

フィルタクラスを定義

# filters.py
import django_filters
from .models import Order

class OrderFilter(django_filters.FilterSet):
    date_from = django_filters.DateFilter(field_name="created_at", lookup_expr="gte")
    date_to = django_filters.DateFilter(field_name="created_at", lookup_expr="lte")

    class Meta:
        model = Order
        fields = ["customer_name", "date_from", "date_to"]

ViewSet に適用

# views.py
from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
from .models import Order
from .serializers import OrderSerializer
from .filters import OrderFilter

class OrderViewSet(viewsets.ModelViewSet):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_class = OrderFilter

実行例

GET /api/orders/?customer_name=株式会社テスト&date_from=2024-01-01&date_to=2024-01-31

2. キーワード検索(部分一致)

フィルタだけでなく「フリーワード検索」を加えると便利。

from rest_framework import filters

class OrderViewSet(viewsets.ModelViewSet):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    filter_backends = [DjangoFilterBackend, filters.SearchFilter]
    filterset_class = OrderFilter
    search_fields = ["customer_name"]

実行例:

GET /api/orders/?search=テスト

部分一致でヒットする。


3. ソート(並び替え)

検索結果を並び替えたいときは OrderingFilter を使う。

from rest_framework import filters

class OrderViewSet(viewsets.ModelViewSet):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_class = OrderFilter
    search_fields = ["customer_name"]
    ordering_fields = ["created_at", "total_amount"]
    ordering = ["-created_at"]  # デフォルト

実行例:

GET /api/orders/?ordering=total_amount
GET /api/orders/?ordering=-created_at

4. ページネーション

大量データを扱う場合はページネーションが必須。

設定でグローバルに指定

# settings.py
REST_FRAMEWORK = {
    "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
    "PAGE_SIZE": 50
}

レスポンス例

{
  "count": 120,
  "next": "http://example.com/api/orders/?page=2",
  "previous": null,
  "results": [
    { "id": 1, "customer_name": "株式会社テスト", "total_amount": 50000 },
    { "id": 2, "customer_name": "サンプル商事", "total_amount": 120000 }
  ]
}

他のページネーション方式

  • LimitOffsetPagination: ?limit=10&offset=20
  • CursorPagination: 大量データでも安定、無限スクロール向け

5. 業務システムでの工夫

  • 複数条件を組み合わせやすい設計
    django-filter でフィールドごとにフィルタ定義
  • 検索条件の履歴保存
    → フロントと組み合わせて「前回の条件を再現」できるようにする
  • 一覧と集計の使い分け
    → 大量データを返すより「条件で絞って集計値だけ返す」API を分けた方が効率的

AI活用の進め方

フィルタリングや検索処理も、AI と相性が良い分野。
ただし、注意すべき点がいくつかある。

  • 最初はおまかせで依頼する
    たとえば「django-filter を使った検索を実装して」と伝えれば、基本的な雛形はすぐ生成される。

  • 既存のフィルタクラスを例示する
    プロジェクト固有のフィールド名や検索条件がある場合は、その一部を例示して「同じ形式で追加して」と指示すると精度が上がる。

  • 複雑な検索条件は分割して依頼する
    AND / OR 条件、外部キーをまたぐ検索、集計 API などは AI が苦手なケース。
    この場合は「まず単純な検索を作る」「次に集計専用 API を作る」と段階的に依頼した方が確実。

AI は定番の検索やページネーション実装を素早く書くのに非常に有効だが、
「どこまで API で返すか」「どこからはフロント側で処理するか」 は設計判断が必要。
この線引きをエンジニアが明確にしないと、AI が出力したコードが使いづらくなる。


まとめ

DRF でフィルタリングと検索を実装する際のポイントは次の通り。

  • django-filter を使えば検索条件を簡単に定義できる
  • SearchFilterOrderingFilter でキーワード検索・並び替えが可能
  • ページネーションを組み合わせて大量データに対応する
  • 業務システムでは「検索条件の履歴」「集計 API」といった工夫も有効
  • AI 活用では雛形生成に頼りつつ、複雑条件は設計を分けて指示するのが効率的

次回は パフォーマンス改善と N+1 対策 をテーマにまとめる予定。

Discussion