djangoで発生するエラー(例外)とその原因です.
エラーの9割くらいはtypoが原因ですので,原因箇所の文字列に打ち間違えがないかよくチェックしましょう.
レアなケースですが,特殊文字が挟まっていて原因がわからない(わかりにくい)ことがあるので,
editorは特殊文字を表示できるものを使いましょう.
tl;dr
- 原因はほぼtypo(タイプミス,打ち間違い)
- エラーの場所と原因は(ほとんどの場合)ちゃんと教えてくれてる → 英語だけどがんばって読め
- ロジックのミスはエラーじゃないです.プログラムは書いた通りに動きます
エラー表示と友達になろう
「なんか動かないんだけど!」「エラーが発生しました!」
原因はちゃんと書いてくれるので,読んでみましょう.
大体は英語ですが, 「どこで」「なにを」間違えているか読み取れれば十分です.
ターミナルに表示されるエラーの読み方
$ python manage.py runserver
と打った時に発生するエラーはdjangoというよりもpythonのエラーがほとんどのはずです.
manage.py
は初期化時に urls.py
や models.py
を読み込みます.
また, urls.py
は views.py
を importして使用します.
この中のファイルに構文エラーなどがあればターミナルに英語が大量に表示され,動作が停止します.
$ python manage.py runserver
Performing system checks...
Unhandled exception in thread started by <function check_errors.<locals>.wrapper at 0x102037d08>
Traceback (most recent call last):
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/site-packages/django/utils/autoreload.py", line 225, in wrapper
fn(*args, **kwargs)
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/site-packages/django/core/management/commands/runserver.py", line 117, in inner_run
self.check(display_num_errors=True)
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/site-packages/django/core/management/base.py", line 379, in check
include_deployment_checks=include_deployment_checks,
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/site-packages/django/core/management/base.py", line 366, in _run_checks
return checks.run_checks(**kwargs)
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/site-packages/django/core/checks/registry.py", line 71, in run_checks
new_errors = check(app_configs=app_configs)
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/site-packages/django/core/checks/urls.py", line 13, in check_url_config
return check_resolver(resolver)
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/site-packages/django/core/checks/urls.py", line 23, in check_resolver
return check_method()
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/site-packages/django/urls/resolvers.py", line 396, in check
for pattern in self.url_patterns:
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/site-packages/django/utils/functional.py", line 37, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/site-packages/django/urls/resolvers.py", line 533, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/site-packages/django/utils/functional.py", line 37, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/site-packages/django/urls/resolvers.py", line 526, in urlconf_module
return import_module(self.urlconf_name)
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 728, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/Users/shimomura/elv/tutorial/tutorial/urls.py", line 33, in <module>
url(r'^polls/', include('polls.urls', namespace='polls')),
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/site-packages/django/urls/conf.py", line 34, in include
urlconf_module = import_module(urlconf_module)
File "/Users/shimomura/.virtualenvs/tutorial/lib/python3.7/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 728, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/Users/shimomura/elv/tutorial/polls/urls.py", line 8, in <module>
url(r'^$', views.idex, name='index'),
AttributeError: module 'polls.views' has no attribute 'idex'
ずらずら表示されているものは スタックトレース(Stack Trace) というもので,プログラムの呼び出し順序が記録されてものです.
pythonではこの表示に traceback という標準ライブラリが使用されるため,最初のほうに
Traceback (most recent call last):
と表示されています.
上から順番に,どのファイルの,何行目の,どの関数(メソッド)から呼び出されたかが書いてますが,
必要なのは 最終的にどこでエラーが発生したか と どういう内容か だけなので
一番下のこの2行以外見る必要ありません.
場合によってはライブラリがエラーの発生元になっており,自分が書いたコードではない場合があります.
その場合は File に自分が編集したファイルが出てくるまで数行さかのぼりましょう.
後述しますが,ブラウザでエラーが見える場合は自分のコードはハイライトされます.
File "/Users/shimomura/elv/tutorial/polls/urls.py", line 8, in <module>
url(r'^$', views.idex, name='index'),
AttributeError: module 'polls.views' has no attribute 'idex'
上の行が最終的にエラーが発生した場所,下の行がエラーの種類とその詳細です.
エラー画面の読み方
$ python manage.py runserver
実行後,
ブラウザでページを開いた時にエラーが発生した場合は専用のエラー画面が表示されます.
ターミナル上にも先程のようにスタックトレースとエラー内容が表示されますが,
ブラウザ上ではより多くの情報が見やすく表示されているので, runserver が成功しているのであれば
この画面から確認するほうがいいでしょう.
とはいえ,見るべきポイントは先程と同じくスタックトレース(Traceback)の一番下と,エラーの種類くらいです.
'Local vars
をクリックするとその関数(メソッド)内で使用している変数の内容が表示されるので,
ranse Exception` などとコードを書いてわざと例外を発生させることで
所謂printfデバッグ的なこともできます.
Python組み込みのエラー
下記のように条件分岐の中で定義した変数は条件を通らない場合使えないので注意してください.
if False:
x = 10
print(x) # NameErrorが発生
AttributeError
pythonではクラスやモジュールの属性に .
で繋いでアクセスしますが,指定した属性を持っていない時にこのエラーが発生します.
モジュールの属性とはファイル内にインデントなしで記述した変数,関数,クラスなどのことです.
a = 10
def my_func():
pass
class MyClass(object):
pass
import hoge
hoge.a # ok
hoge.my_func() # ok
hoge.MyClass() # ok
hoge.b # <-- AttributeError
urls.pyで発生することが多いと思います.
.
の後ろの文字がtypoしているので,関数名などが間違えていないか確認しましょう.
エラー例
File "/Users/shimomura/elv/tutorial/polls/urls.py", line 8, in <module>
url(r'^$', views.idex, name='index'),
AttributeError: module 'polls.views' has no attribute 'idex'
from . import views
...
url(r'^$', views.idex, name='index'),
# ↑ indexのtypo
ImportError
その名の通り,importできなかった,というエラーです.
モジュール名(=ファイル名)をtypoしてます.
ファイルやディレクトリ名をもう一度確認しましょう.
エラー例
File "/Users/shimomura/elv/tutorial/polls/urls.py", line 3, in <module>
from . import view
ImportError: cannot import name 'view' from 'polls' (/Users/shimomura/elv/tutorial/polls/__init__.py)
この場合は views
が view
になってます.
Traceback (most recent call last):
File "./manage.py", line 8, in <module>
from django.core.management import execute_from_command_line
ImportError: No module named django.core.management
こんな感じで django
がないって言われたら仮想環境へ入れてないか,まだインストールしていないのが原因です.
循環importのエラー(ImportError / AttributeError)
ソースとしては特に問題がなさそうでも,循環importしている場合は名前解決ができないので発生します.
File "/Users/shimomura/elv/tutorial/polls/models.py", line 5, in <module>
from . import views
File "/Users/shimomura/elv/tutorial/polls/views.py", line 10, in <module>
from .forms import MyForm
File "/Users/shimomura/elv/tutorial/polls/forms.py", line 3, in <module>
from .models import Question
ImportError: cannot import name 'Question' from 'polls.models' (/Users/shimomura/elv/tutorial/polls/models.py)
views.py
から models.py
を importし, さらに models.py
から views.py
をimportした場合,上記のようになります.
使っている箇所によってImportErrorになったりAttributeErrorになったりします.
typoが無さそうなのにエラーになっている場合は相互にimportしていないか確認してみてください.
SyntaxError
構文エラーです.
pythonの基本的な構文を間違えてます.
エラーが出ている箇所をよく見てみましょう.
実際の原因は前の行の場合もよくあるので,エラーが見つからなければ少し前の行も見てみましょう.
エラー例
File "/Users/shimomura/elv/tutorial/polls/views.py", line 24
if True
^
SyntaxError: invalid syntax
if文の最後に :
がないです.
File "/Users/shimomura/elv/tutorial/polls/views.py", line 24
x = 10
^
SyntaxError: invalid character in identifier
全角スペースが入っていると invalid character in identifier
とメッセージが変わります.
最初のうちは見つけるのがなかなか大変ですが,pythonは明示的にメッセージを出してくれるので割とわかりやすいです.
全角スペースを明示してくれるエディタを使いましょう.
ブラウザのせいかqiitaのせいかわからないですが,全角スペースがコピペできなかったです
IndentationError
これも一種のSyntaxErrorですが,より具体的です.
インデントが揃ってなかったり,下げすぎてたりすると発生します.
File "/Users/shimomura/elv/tutorial/polls/views.py", line 25
return render(request, 'polls/index.html', {
^
IndentationError: unexpected indent
def index(request):
x = 10
return render(request, 'polls/index.html', {
'questions': Question.objects.all(),
})
この場合は x = 10
の行とその次の return
の行のindentが揃ってないです.
エラーが出ているのはreturn
の行ですが, x = 10
の行はスペースが3つしなかいので,実はこの行が原因です.
File "/Users/shimomura/elv/tutorial/polls/views.py", line 25
return render(request, 'polls/index.html', {
^
IndentationError: unindent does not match any outer indentation level
def index(request):
x = 10
return render(request, 'polls/index.html', {
'questions': Question.objects.all(),
})
indentを8個にするとエラーメッセージが変わります.
TabError
File "/Users/shimomura/elv/tutorial/polls/views.py", line 26
Question.objects.get(pk=100)
^
TabError: inconsistent use of tabs and spaces in indentation
indentがスペースじゃなくtabになっている場合に発生します.
NameError
定義していない名前の変数を代入しようとしたり,引数で指定すると発生します.
引数で受け取った request を使おうとして reqest などとtypoして発生します.
File "/Users/shimomura/elv/tutorial/polls/views.py", line 21, in index
x = y
NameError: name 'y' is not defined
KeyError
辞書を参照する際に,存在しないkeyを触ると発生します.
d = {}
x = d['hoge'] # KeyError
KeyErrorを発生させたくない場合は in で存在確認するか, get を使います.
if 'hoge' in d:
x = d['hoge']
# もしくは
x = d.get('hoge')
UnicodeDecodeError
bytes 型を str 型に変換する際に,変換できない文字が含まれていると発生します.
uft8
だと思ったら sjis
だった,というふうにファイル読み込み時に文字コードを間違えると発生します.
UnicodeEncodeError
str 型から bytes 型に変換する際に,変換できない文字が含まれていると発生します.
csvの出力を作る際は文字コードをexcelで開けるようにsjisで出力することがよくありましたが,
梯子高(高の旧字体)の高橋さんなど,機種依存文字が入っていると発生します.
ちなみに変換時に第2引数をつけることでエラーを発生させなくできます.
djgnao初期化時のエラー
# 色々書こうとしたけど結局ほとんどAttributeErrorやImportErrorだった…
# 何かわけわからないエラーが出たって人は教えてください
RuntimeError("populate() isn't reentrant")
初期化が正常に終了しなかった場合に発生します.
初期化途中に発生した例外をdjangoが握りつぶした上で発生するので,とても見つけにくいです.
独自のFieldクラス等を定義して,そのコードに不備があった場合に発生した気がしますが,
発生条件覚えてないので発生した人教えてください.
Viewやテンプレートのエラー
./manage.py runserver
成功後,
ランタイムエラーって書こうとしたけどスクリプト言語だと全部ランタイムでまさかられそうだったので…
TemplateDoesNotExist
render関数などに渡したtemplateのパスが間違っている場合に発生します.
指定した文字列をtypoしている場合と,設定の問題で正しくファイルを探せていない場合があります.
特に manage.py runserver
を実行したまま新しくテンプレート用のディレクトリを作成した場合は読み込めていない場合があるので
コマンドを再実行してみましょう.
エラー内容の中にどこからファイルを探したかが出ているので,そこを確認すれば大丈夫です.
render関数の呼び出しは複数行になることが多いと思いますが,
その場合スタックトレースの呼び出し元が微妙にずれて表示されることがあります.
クリックすれば前後の内容が表示されます.
NoReverseMatch
template内で使用している {% url %}
タグや django.shortcuts.redirect 関数に渡した名前を解決出来ない時に発生します.
- 指定した名前をtypoしている
- urls.pyの
name=
の部分をtypoしている - namespaceがない
などが原因です.
モデル操作時のエラー
Modelクラスを操作する際に発生するエラー
DoesNotExist
Managerクラス(QuerySet)の get
メソッドを使用した際に,条件に一致するデータがDBにない場合に発生します.
URL等でユーザから入力される数値を元に検索している場合はチュートリアル通りキャッチして http404 を投げるようにしましょう.
MultipleObjectsReturned
DoesNotExist と似てますが,今度は複数のデータが見つかった場合に発生します.
画像の例では6個みつかっています.
getメソッドでは複数のデータを扱うことができないので,条件にはpkのようなunique制約のあるフィールドを使うようにしましょう.
pkは
primary key
の略で,DBで主キーとして使用されるフィールドです.
djangoではデフォルトでid
という名前のフィールドで作成されますが,get(pk=1)
のように使うことも出来ます.
FieldError
getやfilterで指定したフィールド名が間違っています.
エラーの詳細に指定可能なフィールド名も書かれているので見比べてみましょう.
httpエラー
今まではhttp的にはステータスコード500を返す,サーバエラーでした.
この節では400番代のステータスコードに対応する例外と,発生した場合の原因について説明します.
djangoでは特殊な例外が内部で発生した場合,
django.core.handler.exception.response_for_exception
の中で捕まえて,
専用のエラーページを表示しています.
ほとんどのケースでは自分で設定するものなのでurls.pyの指定ミスによる404以外では困ることはないと思います.
例外の紹介だけで詳細は省きます.
Http404
urlに対応するviewがない場合に発生する例外です.
原因はurlの設定もしくはブラウザに指定したURLのtypoです.
url的には正しくても,データの都合でこの例外を発生させることもあります.
詳細ページなどではURLでデータのpkを指定しますが,対応するデータがない場合はこの例外を出します.
その他にも403(権限なしエラー)の代わりに,ページの存在を知らせない意味で404にする場合もあります.
PermissionDenied
権限なしエラーです.
httpステータスコードとしては403になります.
400系
Bad Reuqestを表す400ですが,内部的には原因により例外が分かれています.
DisallowedHost
debugモードではない時に settings.py
の ALLOWED_HOSTS の値が正しく設定されていないと発生.
TooManyFieldsSent
getやpostで送付するフィールド数が一定数エラーの場合に発生.
デフォルトは1000.
RequestDataTooBig
送付するデータが一定以上のサイズの場合に発生するエラー.
デフォルトは2.5MB.
ファイルアップロードではなくパラメータとして送付したデータのサイズ数
MultiPartParserError
その名の通りマルチパートでpostした際のパースエラーです.
jsなどで自前でデータを生成すると遭遇するかもしれません.