Django ORMのID検索入門
get・filter・get_object_or_404
Django ORMでIDを指定してデータを取得する方法と、存在しないIDへの対処法を解説します。
こんな人向けの記事です
- IDを指定して1件のデータを取得したい人
- get, filter, get_object_or_404の使い分けを知りたい人
- 存在しないデータへのエラーハンドリングを理解したい人
Step 1getメソッドでの取得
IDを指定して1件のデータを取得するには、objects.get()メソッドを使用します。
from myapp.models import Company
# IDが1のデータを取得
company = Company.objects.get(id=1)
print(company.name) # 株式会社テスト
print(company.founding_date) # 2024-08-16
get()はQuerySetではなく、モデルのインスタンスを直接返します。そのため、取得結果に対して直接フィールドにアクセスできます。
ポイント: get()はIDだけでなく、任意のフィールドで検索できます。ただし、結果が必ず1件になる条件で使用してください。0件または2件以上の場合はエラーが発生します。
Step 2ビューでの使い方
URLパラメータからIDを受け取り、データを取得するパターンです。
from django.urls import path
from . import views
urlpatterns = [
path("company/<int:pk>/", views.CompanyDetailView.as_view(), name="company_detail"),
]
from django.views import View
from django.shortcuts import render
from .models import Company
class CompanyDetailView(View):
def get(self, request, pk):
company = Company.objects.get(id=pk)
context = {"company": company}
return render(request, "myapp/company_detail.html", context)
URLに含まれる<int:pk>の部分がビューの引数pkとして渡されます。これを使ってget(id=pk)でデータを取得します。
Step 3テンプレートでの表示
get()で取得したデータは1件のインスタンスなので、繰り返し処理なしで直接フィールドにアクセスできます。
<h1>会社詳細</h1>
<table>
<tr>
<th>ID</th>
<td>{{ company.id }}</td>
</tr>
<tr>
<th>会社名</th>
<td>{{ company.name }}</td>
</tr>
<tr>
<th>設立日</th>
<td>{{ company.founding_date }}</td>
</tr>
</table>
<a href="{% url 'myapp:company_list' %}">一覧に戻る</a>
Step 4存在しないIDの処理
存在しないIDでget()を呼び出すと、DoesNotExist例外が発生します。適切なエラーハンドリングが必要です。
from django.shortcuts import render, redirect
from django.contrib import messages
from .models import Company
class CompanyDetailView(View):
def get(self, request, pk):
try:
company = Company.objects.get(id=pk)
except Company.DoesNotExist:
messages.error(request, "指定された会社は存在しません")
return redirect("myapp:company_list")
context = {"company": company}
return render(request, "myapp/company_detail.html", context)
注意: get()は2つの例外を発生させる可能性があります。Model.DoesNotExist(0件の場合)とModel.MultipleObjectsReturned(2件以上の場合)です。IDによる検索では後者は通常発生しませんが、他のフィールドで検索する場合は注意が必要です。
Step 5get_object_or_404の活用
Djangoには、データが見つからない場合に自動的に404エラーを返す便利なショートカットがあります。
from django.shortcuts import render, get_object_or_404
from .models import Company
class CompanyDetailView(View):
def get(self, request, pk):
# 見つからない場合は自動的に404エラーページを表示
company = get_object_or_404(Company, id=pk)
context = {"company": company}
return render(request, "myapp/company_detail.html", context)
get_object_or_404を使うと、try-exceptを書く必要がなくなり、コードがシンプルになります。実際のWebアプリケーション開発では最も推奨される方法です。
ポイント: get_object_or_404は内部でget()を呼び出し、DoesNotExist例外をHttp404例外に変換します。RESTful APIの設計において、存在しないリソースへのアクセスに404を返すのは正しいHTTPセマンティクスです。
Step 6filterとgetの違い
get()とfilter()は似ていますが、戻り値と挙動が異なります。
| メソッド | 戻り値 | 0件の場合 | 複数件の場合 |
|---|---|---|---|
| get() | モデルインスタンス | DoesNotExist例外 | MultipleObjectsReturned例外 |
| filter() | QuerySet | 空のQuerySet | 全件含むQuerySet |
# get() - 1件のインスタンスを返す
company = Company.objects.get(id=1)
print(company.name) # 直接アクセス可能
# filter() - QuerySetを返す
companies = Company.objects.filter(id=1)
print(companies.first().name) # first()で1件目を取得
# filter()は存在しなくてもエラーにならない
result = Company.objects.filter(id=9999)
print(result.exists()) # False
IDで1件取得する場合はget()、条件に一致するデータを柔軟に取得する場合はfilter()を使い分けます。
まとめ
objects.get(id=pk)でIDを指定して1件のデータを取得できるget()はモデルインスタンスを直接返すため、繰り返し処理なしでフィールドにアクセスできる- 存在しないIDでは
DoesNotExist例外が発生するため、エラーハンドリングが必要 get_object_or_404()を使うと、見つからない場合に自動で404を返せるget()は1件確定の取得、filter()は条件検索に使い分ける