Djangoよくあるエラー集 

djangoで発生するエラー（例外）とその原因です．
エラーの9割くらいはtypoが原因ですので，原因箇所の文字列に打ち間違えがないかよくチェックしましょう．
レアなケースですが，特殊文字が挟まっていて原因がわからない（わかりにくい）ことがあるので，
editorは特殊文字を表示できるものを使いましょう．

# tl;dr
- 原因はほぼtypo(タイプミス，打ち間違い)
- エラーの場所と原因は（ほとんどの場合）ちゃんと教えてくれてる → 英語だけどがんばって読め
- ロジックのミスはエラーじゃないです．プログラムは書いた通りに動きます

# エラー表示と友達になろう

「なんか動かないんだけど！」「エラーが発生しました！」
原因はちゃんと書いてくれるので，読んでみましょう．
大体は英語ですが， 「**どこで**」「**なにを**」間違えているか読み取れれば十分です．

> ![something_happend.jpeg](https://qiita-image-store.s3.amazonaws.com/0/58048/ef67116c-0143-69dd-2a81-ef4a096c2b4a.jpeg)
> わかりやすいエラー表示の例


## ターミナルに表示されるエラーの読み方
`$ python manage.py runserver` と打った時に発生するエラーはdjangoというよりもpythonのエラーがほとんどのはずです．
`manage.py`は初期化時に `urls.py` や `models.py` を読み込みます．  
また， `urls.py` は `views.py` を importして使用します．
この中のファイルに構文エラーなどがあればターミナルに英語が大量に表示され，動作が停止します．

```shell
$ 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](https://docs.python.jp/3/library/traceback.html)** という標準ライブラリが使用されるため，最初のほうに
`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）の一番下と，エラーの種類くらいです．

<img width="990" alt="スクリーンショット 2018-12-15 12.56.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/58048/95abe9d4-e345-7e24-4e89-8c6b04dd9041.png">

> 'Local vars` をクリックするとその関数（メソッド）内で使用している変数の内容が表示されるので，
> `ranse Exception` などとコードを書いてわざと例外を発生させることで
> 所謂printfデバッグ的なこともできます．

# Python組み込みのエラー

[Python公式ドキュメント](https://docs.python.jp/3/library/exceptions.html#bltin-exceptions)


下記のように条件分岐の中で定義した変数は条件を通らない場合使えないので注意してください．

```python
if False:
    x = 10
print(x)  # NameErrorが発生
```

## AttributeError

pythonではクラスやモジュールの属性に `.` で繋いでアクセスしますが，指定した属性を持っていない時にこのエラーが発生します．

モジュールの属性とはファイル内にインデントなしで記述した変数，関数，クラスなどのことです．

```python:hoge.py
a = 10
def my_func():
    pass
class MyClass(object):
    pass
```

```python:fuga.py
import hoge

hoge.a  # ok
hoge.my_func() # ok
hoge.MyClass() # ok

hoge.b # <-- AttributeError
```

urls.pyで発生することが多いと思います．
`.` の後ろの文字がtypoしているので，関数名などが間違えていないか確認しましょう．

### エラー例


```shell
  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:polls.views.py
from . import views
...
    url(r'^$', views.idex, name='index'),
                 #   ↑ indexのtypo
```

## ImportError

その名の通り，importできなかった，というエラーです．
モジュール名（＝ファイル名）をｔｙｐｏしてます．
ファイルやディレクトリ名をもう一度確認しましょう．

### エラー例

```shell
  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` になってます．

---

```shell
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している場合は名前解決ができないので発生します．

```shell
  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していないか確認してみてください．

-参考： [Pythonで循環インポートするとどうなるのか](http://www.freia.jp/taka/blog/python-recursive-import/index.html)


## SyntaxError

構文エラーです．
pythonの基本的な構文を間違えてます．
エラーが出ている箇所をよく見てみましょう．
実際の原因は前の行の場合もよくあるので，エラーが見つからなければ少し前の行も見てみましょう．

### エラー例

```shell
  File "/Users/shimomura/elv/tutorial/polls/views.py", line 24
    if True
          ^
SyntaxError: invalid syntax
```

if文の最後に `:` がないです．

---

```shell
  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ですが，より具体的です．
インデントが揃ってなかったり，下げすぎてたりすると発生します．

```shell
  File "/Users/shimomura/elv/tutorial/polls/views.py", line 25
     return render(request, 'polls/index.html', {
    ^
IndentationError: unexpected indent
```

```python:エラーが出たソースコード
def index(request):
   x = 10
    return render(request, 'polls/index.html', {
        'questions': Question.objects.all(),
    })
```

この場合は `x = 10` の行とその次の　`return` の行のindentが揃ってないです．
エラーが出ているのは`return` の行ですが， `x = 10` の行はスペースが3つしなかいので，実はこの行が原因です．


---
```shell
  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
```

```python:エラーが出たソースコード
def index(request):
        x = 10
    return render(request, 'polls/index.html', {
        'questions': Question.objects.all(),
    })
```

indentを8個にするとエラーメッセージが変わります．

## TabError

```shell
  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を触ると発生します．

```python
d = {}
x = d['hoge']  # KeyError
```

KeyErrorを発生させたくない場合は **in** で存在確認するか， **get** を使います．

```python
if 'hoge' in d:
    x = d['hoge']
# もしくは
x = d.get('hoge')
```

## UnicodeDecodeError

**bytes** 型を **str** 型に変換する際に，変換できない文字が含まれていると発生します．
`uft8` だと思ったら `sjis` だった，というふうにファイル読み込み時に文字コードを間違えると発生します．

## UnicodeEncodeError

**str** 型から **bytes** 型に変換する際に，変換できない文字が含まれていると発生します．
csvの出力を作る際は文字コードをexcelで開けるようにsjisで出力することがよくありましたが，
梯子高(高の旧字体)の高橋さんなど，機種依存文字が入っていると発生します．
ちなみに変換時に第2引数をつけることでエラーを発生させなくできます．

<img width="790" alt="スクリーンショット 2018-12-16 0.37.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/58048/0e5eba07-3f4f-cafe-466e-dfb914332ef0.png">


# djgnao初期化時のエラー

\# 色々書こうとしたけど結局ほとんどAttributeErrorやImportErrorだった…
\# 何かわけわからないエラーが出たって人は教えてください

## RuntimeError("populate() isn't reentrant")

初期化が正常に終了しなかった場合に発生します．
初期化途中に発生した例外をdjangoが握りつぶした上で発生するので，とても見つけにくいです．
独自のFieldクラス等を定義して，そのコードに不備があった場合に発生した気がしますが，
発生条件覚えてないので発生した人教えてください．


# Viewやテンプレートのエラー

`./manage.py runserver` 成功後，
> ランタイムエラーって書こうとしたけどスクリプト言語だと全部ランタイムでまさかられそうだったので…

## TemplateDoesNotExist

render関数などに渡したtemplateのパスが間違っている場合に発生します．
指定した文字列をtypoしている場合と，設定の問題で正しくファイルを探せていない場合があります．
特に `manage.py runserver` を実行したまま新しくテンプレート用のディレクトリを作成した場合は読み込めていない場合があるので
コマンドを再実行してみましょう．
エラー内容の中にどこからファイルを探したかが出ているので，そこを確認すれば大丈夫です．

<img width="1329" alt="スクリーンショット 2018-12-15 19.05.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/58048/26e482ce-0013-cec5-9e27-3265e61564fb.png">

render関数の呼び出しは複数行になることが多いと思いますが，
その場合スタックトレースの呼び出し元が微妙にずれて表示されることがあります．
クリックすれば前後の内容が表示されます．

<img width="741" alt="スクリーンショット 2018-12-15 19.09.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/58048/c9fb7371-9c31-c6f3-d359-a2f5766e434d.png">

## NoReverseMatch

template内で使用している `{% url %}` タグや **django.shortcuts.redirect** 関数に渡した名前を解決出来ない時に発生します．
  - 指定した名前をtypoしている
  - urls.pyの `name=`の部分をtypoしている
  - namespaceがない
などが原因です．

<img width="793" alt="スクリーンショット 2018-12-15 19.57.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/58048/d128c42f-f49d-4a6b-bed4-c34198d4fe1e.png">

# モデル操作時のエラー

Modelクラスを操作する際に発生するエラー

## DoesNotExist

Managerクラス（QuerySet）の `get` メソッドを使用した際に，条件に一致するデータがDBにない場合に発生します．
URL等でユーザから入力される数値を元に検索している場合はチュートリアル通りキャッチして **http404** を投げるようにしましょう．

<img width="399" alt="スクリーンショット 2018-12-15 19.35.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/58048/2ed77c08-8eeb-95a2-b346-d78c31b87119.png">

## MultipleObjectsReturned

**DoesNotExist** と似てますが，今度は複数のデータが見つかった場合に発生します．
画像の例では6個みつかっています．
getメソッドでは複数のデータを扱うことができないので，条件にはpkのようなunique制約のあるフィールドを使うようにしましょう．

> pkは `primary key` の略で，DBで主キーとして使用されるフィールドです．
> djangoではデフォルトで `id` という名前のフィールドで作成されますが， `get(pk=1)` のように使うことも出来ます．

<img width="544" alt="スクリーンショット 2018-12-15 19.43.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/58048/ed79afe2-e1c8-82e3-5a02-774977478bb5.png">

## FieldError

getやfilterで指定したフィールド名が間違っています．
エラーの詳細に指定可能なフィールド名も書かれているので見比べてみましょう．

<img width="937" alt="スクリーンショット 2018-12-15 19.47.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/58048/edb5cd08-4352-b2b2-ea12-6e6bcc8937c8.png">

# httpエラー

今まではhttp的にはステータスコード500を返す，サーバエラーでした．
この節では４００番代のステータスコードに対応する例外と，発生した場合の原因について説明します．
djangoでは特殊な例外が内部で発生した場合，
`django.core.handler.exception.response_for_exception` の中で捕まえて，
専用のエラーページを表示しています．

ほとんどのケースでは自分で設定するものなのでurls.pyの指定ミスによる404以外では困ることはないと思います．
例外の紹介だけで詳細は省きます．

## Http404

urlに対応するviewがない場合に発生する例外です．
原因はurlの設定もしくはブラウザに指定したURLのtypoです．

<img width="595" alt="スクリーンショット 2018-12-15 19.01.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/58048/fb668734-6e84-3aaf-5a4e-d71a4f88e292.png">

url的には正しくても，データの都合でこの例外を発生させることもあります．
詳細ページなどではURLでデータのpkを指定しますが，対応するデータがない場合はこの例外を出します．
その他にも403（権限なしエラー）の代わりに，ページの存在を知らせない意味で404にする場合もあります．

<img width="401" alt="スクリーンショット 2018-12-15 23.43.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/58048/333ff464-3650-0c2e-fece-c4236f3c0832.png">

## PermissionDenied

権限なしエラーです．
httpステータスコードとしては403になります．

## 400系

Bad Reuqestを表す400ですが，内部的には原因により例外が分かれています．

### DisallowedHost

debugモードではない時に `settings.py` の **ALLOWED_HOSTS** の値が正しく設定されていないと発生．

### TooManyFieldsSent

getやpostで送付するフィールド数が一定数エラーの場合に発生．
デフォルトは1000．

### RequestDataTooBig

送付するデータが一定以上のサイズの場合に発生するエラー．
デフォルトは2.5MB．
ファイルアップロードではなくパラメータとして送付したデータのサイズ数

### MultiPartParserError

その名の通りマルチパートでpostした際のパースエラーです．
jsなどで自前でデータを生成すると遭遇するかもしれません．