2018/07/27
Django モデル データベースDjangoモデルフィールドのnullとblankの違いを理解する
Djangoのモデルフィールドを作成する際のオプションとして、blankとnullを指定することができます。
基本的には、blankはDjangoのフォームからの投稿が空かどうかを判定するもの、nullはデータベースの中身が空かどうかを判定するものになります。それぞれ、blank=Trueとnull=Trueのときに、対象が空であることを許容することになります。
なんとなくイメージは掴めると思いますが、blankとnullはどちらも同じような処理をしているようにみえます。なぜこの二つのオプションを別々で指定する必要があるのでしょうか?具体的な例を用いて検証していきましょう。
blankとnullの値を場合分けすると、以下の4つのパターンが存在します。カッコ書きになっているのはデフォルトの値のことで、モデルフィールドにオプションを指定しない限りはそれぞれFalseが指定されることになります。感覚的には、上から順によく出る指定の仕方で、後述しますが4番目のパターンはあまり使うことはないのではないかと思います。
- (blank=False), (null=False)
- blank=True, null=True
- blank=True, (null=False)
- (blank=False), null=True
blank=False, null=Falseのパターン(デフォルト)
モデルフィールドにblankとnullを指定しないと、それぞれFalseとなるため、特になにもしない限りはこのパターンが一番多くなると思います。
直訳すると、フォームからの投稿時にこのフィールドの入力は必須です、データベースに保存される値も空になってはいけません。ということになります。
これはよくあるケースで、例えばアカウント作成時にユニークなEメールをそれぞれのユーザーが必ず登録する必要がある場合などが考えられます。アカウント作成フォームの入力時にEメールアドレスを必ず入力してもらいたいですし、なにかしらのデータベースの操作で、Eメールアドレスのフィールドが間違えて消去されてしまった、なんてことも起きてほしくないですよね。
blank=True, null=Trueのパターン
こちらもよく利用されるパターンです。
要するに、フォームから投稿するときにこのフィールドの入力は必須ではありません、データベースに保存される値になにも入っていなくても大丈夫です。ということになります。
ここでの、データベースに保存される値になにも入っていない状態というのは、データベースにnullが保存されている状態と同義です。これが、null=Trueを指定する意味になります。
具体的なケースとしては、アカウント作成時に、オプションでユーザーの年齢を登録できるようにすることなどがあげられます。ユーザーとしてはアカウント作成フォームで年齢を入力しなくてもきちんとアカウントを作成することができますし、その場合にはデータベースの年齢フィールドにnullが保存される形になります。
blank=True, null=Falseのパターン(blank=Trueのみの指定)
これは少し特殊なパターンです。
他のパターンと同様にわかりやすい言葉にして見ると、フォームから投稿するときにはこのフィールドの入力は必須ではありません、しかし、データベースに保存される値が空になってはいけません。になります。
しかしちょっと待ってください。投稿フォームでそのフィールドの値を入力しなければ、データベースには何も保存するものがない、つまり、空になってしまうのでは、と思いませんか?
実はそのとおりで、Djangoでよく利用されるDateFieldやImageFieldなどの文字列以外のフィールドではエラーが出てしまいます。しかし、CharFieldやTextFieldのような文字列値においては、空の値はnullではなくて空文字列として保存されます。そのため、文字列を扱うフィールドに限っては、blank=Trueのみの指定を許すことができるのです。
blank=False, null=Trueのパターン(null=Trueのみの指定)
最後のパターンです。
直訳すると、フォームからの入力時には必ずこのフィールドを入力する必要があります、しかし、データベースの値は空であっても構いません。ということです。これのパターンを使う機会はかなり少ないのではないかと思います。
まとめ
このエントリーでは、Djangoにおけるblankとnullの違いと、その使い分けを具体的にみていきました。Djangoのモデルの設計時に必ず考える必要のあるポイントですので、しっかりと理解した上で使いこなしていきましょう。