やりたいこと
DjangoのSerializerで、
空文字とNoneと、ついでに未入力も許容する文字列バリデータをつくる
結論
CharFieldを定義するときに、
requiredだけでなく allow_blank, allow_null も設定しよう(でも罠がある)
class TestSerializer(serializers.Serializer): hoge = serializers.CharField(required=False, allow_blank=True, allow_null=True)
>>> serializer = TestSerializer(data={}) >>> serializer.is_valid() True >>> serializer2 = TestSerializer(data={'hoge': ''}) >>> serializer.is_valid() True >>> serializer3 = TestSerializer(data={'hoge': None}) >>> serializer.is_valid() True
やってみること
テストのためにシリアライザを用意しました。
class TestSerializer(serializers.Serializer): hoge = serializers.CharField()
ここから ""(空文字)、None、そもそも値がない の3パターンが通るようにしていきます。
今の状態でバリデーションをかけてみる
>>> from fuga.serializers import TestSerializer >>> serializer = TestSerializer(data={}) >>> serializer.is_valid() False >>> serializer = TestSerializer(data={'hoge': ''}) >>> serializer.is_valid() False >>> serializer = TestSerializer(data={'hoge': None}) >>> serializer.is_valid() False
すべてFalseになります。
試したこと
CharFieldには状態の異なる「空」を許容するオプションが3つあります。
それらを全て許容状態にしていきます。
1. required
required はすべてのフィールドクラスに共通するバリデートで、
”引数がシリアライザに渡されたかどうか”だけを見ます。
どんな値が入っているかはチェックしません。
デフォルトはTrue。
class TestSerializer(serializers.Serializer): hoge = serializers.CharField(required=False)
>>> serializer = TestSerializer(data={})
>>> serializer.is_valid()
True
これでまず、そもそも値が存在しない場合がクリア。
2 allow_blank
allow_blank は空文字とNoneを許容するバリデートで、デフォルトはFalseです。
CharFieldでは allow_null が非推奨で、こちらが推奨されています。
class TestSerializer(serializers.Serializer): hoge = serializers.CharField(allow_blank=True)
>>> serializer = TestSerializer(data={'hoge': ''}) >>> serializer.is_valid() True >>> serializer2 = TestSerializer(data={'hoge': None}) >>> serializer.is_valid() True
3. allow_null
allow_null はすべてのフィールドクラスに実装されているバリデートです。
nullを許容するか否かだが、CharFieldでは空文字かnullかの判定になります。
デフォルトはFalse。
上で述べたように、CharFieldでは非推奨とされているようです。
class TestSerializer(serializers.Serializer): hoge = serializers.CharField(allow_null=True)
serializer = TestSerializer(data={'hoge': None}) serializer.is_valid() True serializer2 = TestSerializer(data={'hoge': ''}) serializer.is_valid() True
注意点
allow_blankとallow_nullは上で書いたように、
一つずつオプション指定をすると、
空文字とnullの両方を許容する挙動でした。
しかししかし、required=False と組み合わせると、
allow_blankはnullを、allow_nullは空文字を許容しなくなりました。
どういうことなの……
class TestSerializer(serializers.Serializer): hoge = serializers.CharField(required=False, allow_null=True)
s = TestSerializer(data={'hoge': ''}) s.is_valid() False s2 = TestSerializer(data={'hoge': None}) s2.is_valid() True
class TestSerializer(serializers.Serializer): hoge = serializers.CharField(required=False, allow_blank=True)
s = TestSerializer(data={'hoge': ''}) s.is_valid() True s2 = TestSerializer(data={'hoge': None}) s2.is_valid() False
Serializer fields - Django REST framework
では、
It is valid to set both allow_blank=True and allow_null=True, but doing so means that there will be two differing types of empty value permissible for string representations
とあるため、2つセットしたときの挙動のほうが正しそう…?な気がします。
ただ、2つ使う時はバグに気をつけろ的記述もあるため注意したいところ。
上記の挙動を踏まえて、とりあえず今回はallow_blankもallow_nullもセットしましたが、
厳密なチェックを行う場合は注意してください。