【Django】models.Fieldのnull引数とblank引数の違い

null引数とblank引数の違いの説明ページアイキャッチ

このページにはプロモーションが含まれています

このページでは、models.Field のサブクラスのコンストラクタ、すなわちモデルクラスのフィールドに指定可能な null 引数と blank 引数について説明していきたいと思います。

Django では、models.py でのモデルクラスの定義によってデータベースのテーブルの形式を定義することができます。具体的には、モデルクラスに定義したフィールドと同等のフィールド(カラム)を持つテーブルを定義することができます。

モデルクラスとテーブルの関係性を示す図

そして、このモデルクラスのフィールドは、モデルクラスに models.Field のサブクラスのインスタンスを参照するクラス変数を定義することで実現できます。そして、models.Field のサブクラスのインスタンスを生成するのに、models.Field のサブクラスのコンストラクタを実行することになります。そして、このコンストラクタには  null 引数と blank 引数が指定可能です。

フィールドにnull引数とblank引数が指定可能であることを示す図

他の言語で NULL について学んだことのある方であれば、もしかしたらこれらの引数に同じようなイメージを持つ方もおられるかもしれませんが、これらは明確に異なる引数になります。このページでは、これらの null 引数と blank 引数の違い・意味合いについて説明していきます。

また、上記に登場した「モデルクラス」に関しては、別途下記ページで詳細を解説していますので、モデルクラスについて復習したい方は是非下記ページを読んでみてください。

モデルの解説ページアイキャッチ 【Django入門6】モデルの基本

null 引数と blank 引数の違い

それでは、 null 引数と blank 引数の違いについて説明していきたいと思います。

以降では、models.Field のサブクラスのコンストラクタのことを単に「フィールド」と記して説明していきます。

まず、これらは、フィールドに指定可能な引数であるという点は共通です。その一方で、データベースのテーブルに作用するか、フォームに作用するかという点が異なります。

null 引数は「テーブル」の設定を行う引数

null 引数は、テーブルのフィールドに関する設定を行う引数となります。

前述の通り、モデルクラスはテーブルに対応しており、テーブルはモデルクラスに定義したフィールドと同等のフィールド(カラム)を持つことになります。そして、フィールドへの null 引数の指定により、そのフィールドが空の状態のレコードのテーブルへの保存の可否を設定することが可能となっています。null 引数のデフォルトは False となります。

null引数がテーブルの設定を行うための引数であることを示す図

null=True が指定されている場合は、そのフィールドが空の状態のレコードのテーブルへの保存が可能となります。

ageフィールドにnull=Trueが指定されている場合、ageフィールドが空の状態のレコードがテーブルに保存可能であることを示す図

それに対し、null=False が指定されている場合は、そのフィールドが空の状態のレコードのテーブルへの保存が不可となります。

ageフィールドにnull=Falseが指定されている場合、ageフィールドが空の状態のレコードがテーブルに保存不可であることを示す図

具体的には、null=False が指定されているフィールドが空の状態のレコードをテーブルに保存しようとすると、下記のような例外が発生して保存に失敗することになります。したがって、下記のような例外が発生した場合は、そのフィールドが空であるレコードを保存しようとしていることが問題であるため、そのフィールドを空でないようにしてからレコードを保存してやれば例外が解消されることになります。

django.db.utils.IntegrityError: NOT NULL constraint failed: テーブル名.フィールド名

スポンサーリンク

blank 引数は「フォーム」の設定を行う引数

それに対し、blank 引数は、フォームのフィールドに関する設定を行う引数となります。

Django には、モデルフォームという、モデルクラスからフォームを定義する仕組みが存在します。このモデルフォームでは、ベースとして指定したモデルクラスに定義されたフィールドと同等のフィールドを持つフォームを定義することが可能です(フォームに持たせるフィールドは選択可能です)。

モデルフォームクラスの説明図

そして、この blank 引数は、そのベースとなるモデルクラスのフィールドに対応するフォームのフィールドの設定を行う引数となります。具体的には、そのフォームのフィールドが空である場合の妥当性の検証結果を設定する引数となります。blank 引数のデフォルトに関してもは False となります。

blank=True が指定されている場合は、そのフィールドが空の場合に、妥当性の検証で「妥当である」と判断されるようになります。それに対し、blank=False が指定されている場合は、そのフィールドが空の場合に、妥当性の検証で「妥当でない」と判断されるようになります。

妥当性の検証

また、この妥当性の検証は、フォームの各種フィールドの設定に基づき、ウェブブラウザに表示されたフォームからのデータの送信時にも実施されることになりますし、ウェブアプリがデータを受信したときにも実施されることになります。

妥当性の検証には2種類のものが存在することを示す図

フォームやフォームクラス、さらには妥当性の検証に関しては下記ページで解説していますので、これらについて詳しく知りたい方は下記ページを参照していただければと思います。

Djangoのフォームの解説ページアイキャッチ 【Django入門5】フォームの基本

データ送信時の妥当性の検証

分かりやすいのがフォームからのデータ送信時に実施される妥当性の検証になると思います。フォームからのデータの送信時には、フォームの各種フィールドに入力された値に対して妥当性の検証が行われるようになっています。そして、1つでも入力された値が「妥当でない」と判断された場合、フォームからのデータの送信が行えなくなります。

ウェブブラウザに表示されるフォームでの妥当性の検証の説明図

したがって、blank=True が指定されているフィールドに関しては、そのフィールドが空であっても「妥当である」と判断されることになるため、そのフィールドが空であることが原因でフォームからのデータの送信が不可となることはありません。他のフィールドが全て妥当であれば、そのフィールドが空の状態でもフォームからのデータの送信は実行可能となります。

ageフィールドにblank=Trueが指定されている場合、ageフィールドが空の状態のフォームでもデータの送信が可能であることを示す図

それに対し、blank=False が指定されているフィールドに関しては、そのフィールドが空であれば「妥当でない」と判断されることになるため、そのフィールドが空であればフォームからのデータの送信が不可となります。

ageフィールドにblank=Falseが指定されている場合、ageフィールドが空の状態のフォームではデータの送信が不可であることを示す図

ちなみに、ウェブブラウザに表示されるフォームの各種フィールドに対して妥当性の検証が行われるのは、フォームクラスのフィールドの引数にしたがって各種フィールドのタグが生成されるからになります。blank=False が指定されているフィールドに対応するタグには required 属性が指定されることになるため、空の状態だと妥当でないと判断されることになります。

データ受信時の妥当性の検証

また、前述の通り、Django で開発するウェブアプリにおいては(おそらく他のフレームワーク等で開発するウェブアプリにおいても)、データを受信したときに、受信したデータの妥当性の検証を行うのが一般的です。この妥当性の検証は、受信したデータを引数に指定してフォームクラスのインスタンスを生成し、さらに、そのインスタンスに is_valid メソッドを実行させることで実施することが可能です。

受信したデータの妥当性の検証を実施する様子

で、このように生成したインスタンスに is_valid メソッドを実行させれば、各種フィールドに対して妥当性の検証が実行されることになり、この時に、空のフィールドを「妥当である」or「妥当でない」のどちらと判断するかが、そのフィールドの blank 引数によって決まることになります。is_valid メソッドはフォームクラスのインスタンスから実行されるため、この妥当性の検証に関しても、フォームの設定を行う blank 引数に従って結果が変化することになります。

具体的には、blank=True が指定されているフィールドが空であれば、そのフィールドの値は「妥当である」と判断されることになります。

ageフィールドにblank=Trueが指定されている場合、ageフィールドが空の状態のデータに対する妥当性の検証で妥当であると判断されることを示す図

それに対し、blank=False が指定されているフィールドが空であれば、そのフィールドの値は「妥当でない」と判断されることになります。

ageフィールドにblank=Falseが指定されている場合、ageフィールドが空の状態のデータに対する妥当性の検証で妥当でないと判断されることを示す図

この、”フィールドが空” とは、具体的には、そのフィールド自体が存在しない or フィールドの値が空文字列('')であることを指しています。

2つの妥当性の検証の必要性

ここまで説明してきた通り、blank 引数は、データ送信時、及び、データ受信時に実施される妥当性の検証に作用する引数となります。

もしかしたら、ここまでの説明を読んで、妥当性の検証はデータ送信時のみ行えば良いと考えた人もおられるかもしれません。ですが、データ送信時の妥当性の検証は実施されない可能性があるので、データ受信時の妥当性の検証も必要となります。

例えば、ウェブアプリから受信したフォームでデータを送信する場合は、基本的にはデータ送信時の妥当性の検証が実施されることになります。ですが、フォームを介さず、直接 Python スクリプト等からデータをウェブアプリに送信することも可能で、その場合はデータ送信時の妥当性の検証が行われません。

フォームを介さずにデータをウェブアプリに送信する様子

また、悪意あるユーザーから悪意あるデータが送信されてくる可能性もありますので、データ受信時の妥当性の検証もウェブアプリには必要となります。そして、安全にデータを扱うため、妥当性の検証で「妥当である」と判断された場合のみ、受信したデータを扱った処理(データのレコードとしての保存など)を実施するようにウェブアプリを開発する必要あります。

blank 引数はモデルクラスフォームに対して有効

また、この blank 引数はモデルクラスのフィールドに指定するものであるため、モデルクラスをベースとしてフォームを作成するモデルフォームクラスを定義しない場合は、blank 引数の指定は無意味であることに注意してください。

モデルフォームクラスではなく、単なるフォームクラスを定義し、そのクラスにフィールドを定義するようなことも可能です。この場合には、blank 引数ではなく required 引数によって、フィールドが空の場合の妥当性の検証の結果を設定することになります。required 引数の場合は False 指定した場合に空のフィールドを「妥当である」と判断し、True を指定した場合に「妥当でない」と判断することになり、blank 引数とはTrue / False の意味合いが逆になるので注意してください。

null 引数 x blank 引数の組み合わせとウェブアプリの動作

null 引数と blank 引数の意味合いについては理解していただけたでしょうか?

null 引数と blank 引数には、それぞれ True / False を指定することが可能です(引数を指定しなかった場合は、両方ともデフォルトの False 指定となる)。つまり、各フィールドに対し、null 引数と blank 引数の指定の仕方の組み合わせは4パターン存在することになります。

ここからは、今まで解説してきた内容のおさらいの意味も含め、これらの4つの組み合わせで null 引数と blank 引数を指定した場合のウェブアプリの動作や注意点等について解説していきます。

null=False / blank=False (デフォルト)

まずは、null=False と blank=False を指定するパターンが挙げられます。この組み合わせのパターンはデフォルト設定となります。

考え方も単純で、この場合は、そのフィールドが空であれば妥当でないと判断され、さらに、そのフィールドが空の状態のレコードはテーブルへの保存も不可となります。

blank=False,null=Falseのフィールドが空の場合の、妥当性の検証結果とレコードの保存結果を示す図

基本的に、この組み合わせが一番安全なパターンとなります。なので、null 引数と blank 引数の指定の仕方に迷うのであれば、この組み合わせの引数指定を行うのが一番無難だと思います。

スポンサーリンク

null=True / blank=True

2つ目は null=True と blank=True を指定するパターンになります。

これも考え方も単純で、この場合は、そのフィールドが空の状態でもフォームからの送信が可となります。また、そのフィールドが空のデータをウェブアプリが受信したとしても「妥当である」と判断されることになります。さらに、そのフィールドが空の状態のレコードもテーブルに保存可となります。

blank=True,null=Trueのフィールドが空の場合の、妥当性の検証結果とレコードの保存結果を示す図

つまり、そのフィールドに値を入力するかどうかはユーザーが決めることができます。そして、フィールドが空であったとしても、そのフォームから受信したデータに基づいて生成したレコードをテーブルに保存することが可能となります。

blank=Trueを指定するメリットを説明する図

ただし、これは null=Trueblank=True を指定する他のパターンでも共通して言えることになるのですが、これらを指定したフィールドの場合、妥当性の検証で「妥当である」と判断されたデータであったとしても、データベースから取得したレコードであったとしても、そのフィールドが空(None)である可能性があるという点に注意が必要となります。

保存されているレコードのageフィールドが空の場合、そのレコードを取得して生成されるインスタンスのageの値がNoneとなる様子

そのため、null=Trueblank=True を指定するフィールドの値を扱う処理は、その値が None であることを考慮して実装する必要があります。

blank=False が指定されているフィールドの値は、妥当性の検証で「妥当である」と判断された場合は必ず None 以外の値となるため、妥当性の検証で「妥当である」と判断された後の処理は None であることを考慮せずに実装することができます。また、null=True が指定されているフィールドは空の状態ではテーブルに保存できないため、テーブルから取得したレコードのそのフィールドは必ず None 以外の値となります。なので、テーブルから取得したレコードに関しては、そのフィールドが None であることを考慮せずに扱うことができます。

ですが、null=Trueblank=True を指定したフィールドは、上記のような場合にも、そのフィールドの値が None であることがあるため、まず、そのフィールドが None であるかどうかで条件分岐を行い、None の場合は処理をスキップしたり、デフォルトの値を用いて処理を実施したりする必要があります。

例えば、下記は引数で指定された pk をプライマリーキーとする User のレコードの age フィールドを用いて、その User のレコードが未成年のものであるかどうかを判断する関数となります。age フィールドが IntegerField であり、さらに null=False を指定している場合は age フィールドは None となることが無いため、下記の処理は正常に動作することになります。

未成年かどうかの判断
def is_minor(pk):
    user = User.objects.get(pk=pk)
    if user.age < 18:
        return True
    else:
        return False

ですが、age フィールドに null=True が指定されている場合、age フィールドが空の状態でもレコードとしてテーブルに保存可能です。つまり、テーブルから取得したレコードの age フィールドは空、値としては None である可能性があるということになります。

もし、取得したレコードの age フィールドの値が None であれば、上記の user.age < 18 の箇所で例外が発生することになります。なので、age フィールドに null=True が指定されているのであれば、age フィールドが None である可能性を考慮し、その時に例外が発生しないような処理を実装する必要があります。例えば、次のように age フィールドが None の場合に比較を実施せずに True を返却するようにすれば、とりあえず例外は防げることになります。

未成年かどうかの判断の改善
def is_minor(pk):
    user = User.objects.get(pk=pk)

    if user.age is None:
        return True

    if user.age < 18:
        return True
    else:
        return False

こここまで説明してきたように、null=Trueblank=True を指定することで、ユーザーが不要な入力をスキップできるようになるというメリットが得られる一方で、ウェブアプリ内部の処理が複雑になるというデメリットがあります。もちろん、メリットも大きいので、これらを指定すること自体が NG というわけではないですが、null=Trueblank=True を指定する場合は、そのフィールドの値が None となる可能性を考慮して実装する必要があることは覚えておいてください。

null=False / blank=True

3つ目は null=False と blank=True を指定するパターンになります。

この場合は、そのフィールドが空の状態でもフォームからの送信が可となります。また、そのフィールドが空のデータをウェブアプリが受信したとしても妥当であると判断されることになります。ですが、そのフィールドが空の状態のレコードはテーブルに保存不可となります。

blank=True,null=Falseのフィールドが空の場合の、妥当性の検証結果とレコードの保存結果を示す図

つまり、そのフィールドが空の状態のデータを受信したとしても妥当性の検証では「妥当である」と判断されることになりますが、その受信したデータをそのままレコードとしてテーブルに保存しようとすると基本的には例外が発生することになります。

blank=True を指定することで、ユーザーが不要なフィールドへの入力をスキップできるようになるというメリットは得られるのですが、結局 null=False の効果で、そのデータのレコードとしてのテーブルへの保存時に例外が発生するのであれば意味が無いようにも思えますね。

フィールドが空の状態で送信できたとしてもレコードの保存に失敗してしまうことを示す図

ただ、このテーブルへの保存時の例外を防ぐことができるのであれば、この組み合わせのパターンにも使い道があることになります。

例えば、下記の2つのケースにおいては、そのフィールドが空であってもレコードの保存に成功することになります。

  • そのフィールドが文字列を扱うフィールドである(CharFieldTextField
  • そのフィールドに default 引数が指定されている

前者の場合、空のフィールドは空文字列('')として保存されることになるため、null=False が指定されていても例外が発生しません。後者の場合、空のフィールドは default 引数に指定された値として保存されることになるため、null=False が指定されていても例外が発生しません。また、上記の2つに当てはまらなくても、空のフィールドが送信されてきたときに、そのフィールドに何らかの妥当な値をセットしてからレコードとして保存するようにすれば、空のフィールドが送信されてきたとしても例外の発生を防ぐことが可能です。

このように、空のフィールドが送信されてきたとしても、保存時に自動的に空のフィールドに値がセットされる仕組みを利用したり、空のフィールドに値をセットしてからレコードを保存するような処理を実装したりする場合は、null=False と blank=True の組み合わせが有効になります。ただし、これらが行われない場合、前述の通り、送信されてきたデータをそのままレコードとして保存すると例外が発生することになるので、この点には注意が必要となります。

null=True / blank=False

最後の4つ目は null=True と blank=False を指定するパターンになります。

この場合、そのフィールドが空の状態でのフォームからの送信は不可となり、また、そのフィールドが空のデータをウェブアプリが受信したと場合にも妥当でないと判断されることになります。ですが、そのフィールドが空の状態のレコードもテーブルに保存可となります。

blank=False,null=Trueのフィールドが空の場合の、妥当性の検証結果とレコードの保存結果を示す図

基本的に、ウェブアプリでは送信されてきたデータに対して妥当性の検証を実施し、妥当であると判断された場合のみ、送信されてきたデータをレコードとしてテーブルに保存するようにすることが多いです。したがって、この組み合わせで引数を指定したフィールドは、レコードとしてテーブルに保存するタイミングでは空でないことが保証されていることになります。

つまり、null=True を指定したフィールドが空の状態のレコードが保存されることが基本的にはあり得ないため、null=True を指定しても意味が無いことになります。

そのため、null=True と blank=False の組み合わせで引数を指定する意味はなく、この組み合わせを指定するのであれば、null=False と blank=False の組み合わせを指定した方が良いと思います。

スポンサーリンク

まとめ

このページでは、モデルクラスのフィールドに指定する null 引数と blank 引数の違いについて解説しました!

null 引数は「テーブル」に対する設定を行う引数であり、blank 引数は「フォーム」、特にフォームでの妥当性の検証に対する設定を行う引数となります。この違いを理解した上で、null 引数と blank 引数を指定するようにしましょう!

同じカテゴリのページ一覧を表示