この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:3
ページ更新者:atom
更新日時:2026-06-11 07:07:02

タイトル: エラー一覧
SEOタイトル: Django のよくあるエラー一覧と対処法 — OperationalError から CSRF まで

この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li><strong>OperationalError</strong>: DB 接続不可、 テーブル不在。 settings.py / migrate / DB 起動を確認</li><li><strong>DoesNotExist / MultipleObjectsReturned</strong>: <code>get()</code> の戻り保証なし。 <code>filter().first()</code> や <code>get_or_create()</code> 推奨</li><li><strong>TemplateDoesNotExist</strong>: テンプレートパス・APP_DIRS・TEMPLATE_DIR 確認</li><li><strong>NoReverseMatch</strong>: URL name の typo、 引数数不一致。 <code>{% url "name" arg %}</code> 構文確認</li><li><strong>CSRF token missing / Forbidden 403</strong>: フォームに <code>{% csrf_token %}</code> 必須。 ALLOWED_HOSTS / CSRF_TRUSTED_ORIGINS も</li></ul></td></tr></table>
<h2>1. OperationalError</h2>

<p>DB 関連の最頻出エラー。 接続情報・ネットワーク・テーブル不在など多岐:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">django.db.utils.OperationalError: could not connect to server: Connection refused
django.db.utils.OperationalError: (1045, "Access denied for user &apos;root&apos;@&apos;localhost&apos;")
django.db.utils.OperationalError: no such table: blog_article
django.db.utils.OperationalError: (1146, "Table &apos;mydb.blog_article&apos; doesn&apos;t exist")</code></pre>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#fff3e0"><th>原因</th><th>対処</th></tr></thead>
<tbody>
<tr><td>DB サーバ停止</td><td><code>systemctl status postgresql</code> / MySQL サービス起動</td></tr>
<tr><td>接続情報誤り</td><td>settings.py の HOST/PORT/USER/PASSWORD 再確認</td></tr>
<tr><td>テーブル不在</td><td><code>python manage.py migrate</code> 実行</td></tr>
<tr><td>権限不足</td><td>DB ユーザに <code>GRANT ALL ON dbname.* TO user@host</code></td></tr>
<tr><td>ネットワーク</td><td>ファイアウォール、 セキュリティグループ確認</td></tr>
</tbody>
</table>

<h2>2. IntegrityError</h2>

<p>制約違反(UNIQUE / NOT NULL / FK):</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python"># UNIQUE 制約違反
django.db.utils.IntegrityError: UNIQUE constraint failed: blog_article.slug

# 対処: 重複チェック後に作成
if not Article.objects.filter(slug=slug).exists():
    Article.objects.create(slug=slug, ...)

# または get_or_create
article, created = Article.objects.get_or_create(
    slug=slug,
    defaults={&apos;title&apos;: title, &apos;body&apos;: body},
)

# NOT NULL 制約違反
django.db.utils.IntegrityError: NOT NULL constraint failed: blog_article.author_id

# 対処: 必須フィールドを必ず指定 or モデルに null=True / default 付与</code></pre>
<h2>3. DoesNotExist / MultipleObjectsReturned</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python"># DoesNotExist: get() で見つからない
art = Article.objects.get(pk=999)
# blog.models.Article.DoesNotExist: Article matching query does not exist.

# 対処パターン
# 1. filter().first()
art = Article.objects.filter(pk=999).first()  # 無ければ None

# 2. get_object_or_404 (ビューで便利)
from django.shortcuts import get_object_or_404
art = get_object_or_404(Article, pk=999)

# 3. try/except
try:
    art = Article.objects.get(pk=999)
except Article.DoesNotExist:
    art = None

# MultipleObjectsReturned: get() で複数該当
Article.objects.get(category__slug=&apos;tech&apos;)
# MultipleObjectsReturned: get() returned more than one Article

# 対処: filter() を使う、 または unique 制約見直し
arts = Article.objects.filter(category__slug=&apos;tech&apos;)</code></pre>
<h2>4. TemplateDoesNotExist</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">django.template.exceptions.TemplateDoesNotExist: blog/article_list.html

# テンプレート検索順序:
# 1. TEMPLATES[0][&apos;DIRS&apos;] のフォルダ
# 2. 各 INSTALLED_APPS の templates/ サブフォルダ (APP_DIRS=True 時)</code></pre>
<p>対処:</p>

<ul>
<li>ファイルパスを確認 — <code>blog/templates/blog/article_list.html</code> 構成が定石(アプリ名サブフォルダ)</li>
<li><code>settings.py</code> の <code>TEMPLATES[0]['APP_DIRS']</code> が <code>True</code> か確認</li>
<li>プロジェクト共通テンプレートは <code>BASE_DIR / 'templates'</code> を <code>DIRS</code> に追加</li>
<li>アプリが <code>INSTALLED_APPS</code> に登録されているか確認</li>
</ul>

<h2>5. NoReverseMatch</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">django.urls.exceptions.NoReverseMatch:
Reverse for &apos;article_detail&apos; with arguments &apos;(1,)&apos; not found.
1 pattern(s) tried: [&apos;blog/article/(?P<slug>[-a-zA-Z0-9_]+)/$&apos;]</code></pre>
<p>原因と対処:</p>

<ul>
<li><strong>URL name の typo</strong>: <code>urls.py</code> の <code>name='article_detail'</code> と <code>{% url 'article_detail' %}</code> を一致させる</li>
<li><strong>引数数の不一致</strong>: URL パターンが <code>slug</code> を要求しているのに ID を渡している</li>
<li><strong>namespace 必要</strong>: <code>{% url 'blog:article_detail' slug=art.slug %}</code></li>
<li><strong>include の app_name</strong>: <code>urls.py</code> 冒頭に <code>app_name = 'blog'</code></li>
</ul>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python"># blog/urls.py
from django.urls import path
from . import views

app_name = &apos;blog&apos;                # namespace

urlpatterns = [
    path(&apos;article/<slug:slug>/&apos;, views.detail, name=&apos;article_detail&apos;),
]

# テンプレート
{% url &apos;blog:article_detail&apos; slug=article.slug %}

# Python コード
from django.urls import reverse
reverse(&apos;blog:article_detail&apos;, kwargs={&apos;slug&apos;: art.slug})</code></pre>
<h2>6. CSRF Verification Failed (403)</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">Forbidden (CSRF token missing or incorrect.):
Reason given for failure: CSRF token missing.</code></pre>
<p>POST フォームには必ず <code>{% csrf_token %}</code> 必要:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><form method="post" action="{% url &apos;blog:create&apos; %}">
  {% csrf_token %}                      <!-- 必須 -->
  <input type="text" name="title">
  <button type="submit">送信</button>
</form>

<!-- AJAX の場合 -->
<script>
const csrfToken = document.querySelector(&apos;[name=csrfmiddlewaretoken]&apos;).value;
fetch(&apos;/api/items/&apos;, {
  method: &apos;POST&apos;,
  headers: {
    &apos;X-CSRFToken&apos;: csrfToken,
    &apos;Content-Type&apos;: &apos;application/json&apos;,
  },
  body: JSON.stringify(data),
});
</script></code></pre>
<p>HTTPS 環境での追加対処(settings.py):</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python"># Origin 不一致でも 403 になる
CSRF_TRUSTED_ORIGINS = [
    &apos;https://example.com&apos;,
    &apos;https://*.example.com&apos;,
]
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True</code></pre>
<h2>7. DisallowedHost (ALLOWED_HOSTS)</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">django.core.exceptions.DisallowedHost:
Invalid HTTP_HOST header: &apos;example.com&apos;.
You may need to add &apos;example.com&apos; to ALLOWED_HOSTS.</code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python"># settings.py
ALLOWED_HOSTS = [
    &apos;example.com&apos;,
    &apos;www.example.com&apos;,
    &apos;.example.com&apos;,           # サブドメイン全部
    &apos;127.0.0.1&apos;,
    &apos;localhost&apos;,
]

# 開発時のみ全許可(本番禁止)
if DEBUG:
    ALLOWED_HOSTS = [&apos;*&apos;]</code></pre>
<h2>8. ImproperlyConfigured</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">django.core.exceptions.ImproperlyConfigured:
The SECRET_KEY setting must not be empty.

django.core.exceptions.ImproperlyConfigured:
Requested setting DATABASES, but settings are not configured.
You must either define the environment variable DJANGO_SETTINGS_MODULE...</code></pre>
<p>対処:</p>

<ul>
<li><strong>SECRET_KEY 未設定</strong>: <code>.env</code> から読込み、 または <code>settings.py</code> に直書き(本番は環境変数推奨)</li>
<li><strong>DJANGO_SETTINGS_MODULE 未設定</strong>: <code>os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')</code> を <code>manage.py</code> / <code>wsgi.py</code> 冒頭で</li>
<li><strong>NAME 未設定</strong>: <code>DATABASES['default']['NAME']</code> 必須</li>
</ul>

<h2>9. ProgrammingError / FieldError</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python"># ProgrammingError: 存在しないカラム参照(マイグレーション漏れ)
django.db.utils.ProgrammingError: column blog_article.summary does not exist

# 対処: makemigrations + migrate

# FieldError: 不正なフィールド指定
django.core.exceptions.FieldError: Cannot resolve keyword &apos;titel&apos; into field.
Choices are: author, body, category, created_at, id, slug, ...

# 対処: typo 修正 (titel → title)</code></pre>
<h2>10. MIGRATION 関連</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#fff3e0"><th>症状</th><th>対処</th></tr></thead>
<tbody>
<tr><td>You have unapplied migrations</td><td><code>python manage.py migrate</code></td></tr>
<tr><td>Conflicting migrations detected</td><td><code>python manage.py makemigrations --merge</code></td></tr>
<tr><td>Migrations for 'app' not detected</td><td><code>app/migrations/__init__.py</code> がない、 または <code>INSTALLED_APPS</code> 未登録</td></tr>
<tr><td>Inconsistent migration history</td><td>DB の <code>django_migrations</code> テーブルと不整合。 環境差分の調査が必要</td></tr>
<tr><td>RemovedInDjangoXX warning</td><td>非推奨機能。 Django アップグレード前に対処</td></tr>
</tbody>
</table>

<h2>11. デプロイ後のエラー</h2>

<ul>
<li><strong>500 Internal Server Error</strong>: DEBUG=False で詳細が出ない → ログ確認(<code>/var/log/gunicorn/error.log</code> 等)</li>
<li><strong>Static files 404</strong>: <code>collectstatic</code> 実行漏れ、 nginx の alias 設定誤り</li>
<li><strong>ImportError: Couldn't import Django</strong>: 仮想環境未有効化、 systemd ユニットの <code>EnvironmentFile</code> 誤り</li>
<li><strong>SuspiciousOperation</strong>: ALLOWED_HOSTS / SECURE_PROXY_SSL_HEADER 設定漏れ</li>
</ul>

<h2>デバッグのコツ</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python"># 1. DEBUG=True で詳細表示(開発のみ)
DEBUG = True

# 2. django-debug-toolbar
pip install django-debug-toolbar
INSTALLED_APPS += [&apos;debug_toolbar&apos;]
MIDDLEWARE += [&apos;debug_toolbar.middleware.DebugToolbarMiddleware&apos;]
INTERNAL_IPS = [&apos;127.0.0.1&apos;]

# 3. ログ設定
LOGGING = {
    &apos;version&apos;: 1,
    &apos;disable_existing_loggers&apos;: False,
    &apos;handlers&apos;: {
        &apos;console&apos;: {&apos;class&apos;: &apos;logging.StreamHandler&apos;},
    },
    &apos;loggers&apos;: {
        &apos;django.db.backends&apos;: {
            &apos;level&apos;: &apos;DEBUG&apos;,         # 全 SQL ログ
            &apos;handlers&apos;: [&apos;console&apos;],
        },
    },
}

# 4. shell でモデル検証
python manage.py shell
>>> from blog.models import Article
>>> Article.objects.all()

# 5. check コマンド
python manage.py check
python manage.py check --deploy       # 本番向け追加チェック</code></pre>
<h2>FAQ</h2>

<p><strong>Q: 本番でエラー詳細を見たい</strong><br />
A: DEBUG=False を維持し、 <code>LOGGING</code> でファイル/Sentry に送る。 DEBUG=True 公開は<strong>絶対禁止</strong>(SECRET_KEY 漏洩リスク)。</p>

<p><strong>Q: マイグレーション地獄から抜けたい</strong><br />
A: 開発初期なら全削除して作り直し。 運用後は <code>--squash</code> で履歴圧縮。</p>

<p><strong>Q: 全エラーを Sentry に飛ばしたい</strong><br />
A: <code>sentry-sdk</code> をインストールし、 <code>settings.py</code> で <code>sentry_sdk.init()</code>。 リクエスト情報・スタックトレースが自動収集されます。</p>