Djangoのよくあるエラーと解決方法まとめ。DisallowedHost・NoReverseMatch・マイグレーション矛盾など
Django開発でよく遭遇するエラーの原因と解決方法を、この記事1本にまとめて解説します。
- DisallowedHost(サーバー配置時の定番)
- InconsistentMigrationHistory(CustomUser導入時)
- NoReverseMatch: ‘XXX’ is not a registered namespace
- Generic detail view must be called with either an object pk or a slug
- RuntimeWarning: received a naive datetime
- [Celery] NotRegistered
1. DisallowedHost
ローカルで開発してきたソースをサーバーへ配置すると、ほぼ確実に遭遇するエラーです。
解決方法
settings.py の ALLOWED_HOSTS に、アクセスに使うホスト名(またはIPアドレス)を追記します。
# ALLOWED_HOSTS = []
ALLOWED_HOSTS = ['example.com']
複数指定する場合はカンマ区切り、すべて許可する場合はワイルドカードが使えます。
ALLOWED_HOSTS = ['example.com', '192.0.2.10']
ALLOWED_HOSTS = ['*'] # 開発時のみ。本番では使わない
['*'] はHostヘッダー検証を無効化してしまうため、本番環境では必ず実ホスト名を列挙してください。ローカル・開発・本番でALLOWED_HOSTSを分けたい場合は、settings.pyを環境ごとに分割する方法が便利です。
2. InconsistentMigrationHistory
CustomUserモデルを導入・修正した際に発生します。
django.db.migrations.exceptions.InconsistentMigrationHistory: Migration admin.0001_initial is applied before its dependency user.0001_initial on database 'default'.
原因はマイグレーション履歴の矛盾です。DjangoデフォルトのUserモデルで admin のマイグレーションが先に適用されてしまっており、後から導入したCustomUserモデルとの依存関係を追跡できなくなっています。
解決方法:DBの作り直し(推奨)
開発初期であれば、作成済みのDBを削除してマイグレーションをやり直すのが最も確実です。CustomUserモデルはプロジェクトの最初に導入しておくのが定石です。
回避策:adminのコメントアウト(非推奨)
settings.py と urls.py でadminを無効化すれば一応回避できますが、管理画面が使えなくなり、なぜ無効化したのか履歴も追えなくなるためおすすめしません。
INSTALLED_APPS = [
# 'django.contrib.admin',
'django.contrib.auth',
# ...
]
3. NoReverseMatch: ‘XXX’ is not a registered namespace
NoReverseMatch at / 'XXXXX' is not a registered namespace
テンプレートやreverseで {% url 'polls:index' %} のように名前空間つきでURLを参照しているのに、名前空間が登録されていない場合に発生します。
解決方法
アプリの urls.py に app_name を定義します。
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('<int:question_id>/', views.detail, name='detail'),
]
4. Generic detail view must be called with either an object pk or a slug
Generic detail view XXXXDetailView must be called with either an object pk or a slug in the URLconf.
DetailView(および BaseDetailView)は、URLのパラメータ名として pk または slug しか受け付けません。独自のパラメータ名を使うとこのエラーになります。
解決方法
urls.py のURLパラメータ名を pk に修正します。
# エラーになるパターン
path('detail/<int:app_id>/', XXXXDetailView.as_view(), name='detail'),
# 解消するパターン
path('detail/<int:pk>/', XXXXDetailView.as_view(), name='detail'),
5. RuntimeWarning: received a naive datetime
RuntimeWarning: DateTimeField ItemList.created received a naive datetime
Pythonのdatetimeには、タイムゾーンを持たないnaiveと持つawareの2種類があります。USE_TZ = True の環境でモデルのDateTimeFieldへnaiveなdatetimeを渡すと、この警告が出ます。
解決方法:django.utils.timezoneを使う
Djangoでは django.utils.timezone でawareなdatetimeを簡単に取得できます。datetime.now() の代わりにこちらを使いましょう。
from django.utils import timezone
now_utc = timezone.now() # UTC
now_local = timezone.localtime() # ローカルタイム
標準の datetime パッケージで扱う場合はタイムゾーンを明示します。
import datetime as dt
from zoneinfo import ZoneInfo # Python 3.9未満は pytz を使用
now_utc = dt.datetime.now(dt.timezone.utc)
now_local = now_utc.astimezone(ZoneInfo('Asia/Tokyo'))
ベストプラクティスはawareで保持し、表示時にシステムごとのタイムゾーンへ変換することです。
6. [Celery] NotRegistered
DjangoでCeleryを使ったタスクを追加した際に、タスクは登録できるのに実行すると次のエラーになることがあります。
{"exc_type": "NotRegistered", "exc_message": ["celery_tasks.tasks.hello"], "exc_module": "celery.exceptions"}
解決方法:WorkerとBrokerの再起動
@shared_task でタスクを追加・変更した後は、CeleryのWorkerとBrokerを再起動してください。Workerは起動時にタスクを読み込むため、起動後に追加されたタスクを認識できず NotRegistered となります。
まとめ
| エラー | 対処 |
|---|---|
| DisallowedHost | ALLOWED_HOSTS にホスト名を追記 |
| InconsistentMigrationHistory | DBを作り直す(CustomUserは最初に導入) |
| not a registered namespace | urls.py に app_name を定義 |
| pk or a slug in the URLconf | URLパラメータ名を pk にする |
| naive datetime警告 | django.utils.timezone を使う |
| Celery NotRegistered | Worker/Brokerを再起動 |
認証まわりの実装はdjango-allauth入門ガイドも参考にしてください。