【注意】この記事は2020年11月12日現在Djangoのサポート対象になっているバージョン(2.2・3.0・3.1)を調査対象にして書きました。
DjangoではDEFAULT_CHARSETというContent-Typeのcharsetを指定する設定項目があります。デフォルト値は"utf-8"
ですが、明示的にファイルに書いておこうとして以下のように書くと思わぬトラブルに繋がります。
|
|
RFC 2616の3.4には"HTTP character sets are identified by case-insensitive tokens.“と書いているのでどちらでもよさそうな気はしますが、Djangoではutf-8の場合は必ず小文字の"utf-8"
にしてください。
なぜなら、Djangoの内部ではutf-8であるかを検証するロジックでは小文字の"utf-8"
で判定しているからです。大文字小文字を区別しないようにはなっていません。
具体的にトラブルになるケースを見てみましょう。サンプルアプリケーションで使用する環境は以下のとおりです。
- Python 3.8.6
- Django 2.2.17
- Pillow 8.0.1
以下のようなテストコードを書いたとします。(override_settings
でわざとDEFAULT_CHARSET="UTF-8"
にしています)
|
|
上記テストを実行すると、ビューにリクエストを送る前の段階で以下のエラーが発生します。
|
|
force_bytes
という関数の中でエラーが発生しているようです。force_bytes
のソースコードを見てみましょう。
|
|
本来は94行目のif encoding == 'utf-8':
で真と判定されて入力値s
はそのままリターンされるはずですが、DEFAULT_CHARSET="UTF-8"
にしたために文字列が一致せず、97行目でs.decode
が呼ばれてUnicodeDecodeError
が発生してしまいました。
上記テストはDEFAULT_CHARSET="utf-8"
であればUnicodeDecodeError
は発生しません。
|
|