DRFのシリアライザーでnull値をblankにしたかった
今開発中のアプリでクライアントから受け取ったデータからnullを取り除いて、blankに変更したかった。
流れとしては
- クライアントのフォームから値を送信
- サーバーで値を受け取る
で、1のクライアントからデータを受け取った際、値に何も入っていないデータはnullで届くようになっているが、serializerのバリデーションで弾かれる。
フォームからの送信時にnullをブランクにしても良かったのだが、とりあえずdjango側でnullをblankにcastすることにした。 値を受け取ってからDRFがvalidationを実行しsaveするまでの大まかな流れは以下である
- view
- to_internal_value (serializer)
- save (serializer)
上記の流れから、nullをblankにキャストする際は1のViewまたは2のserializer内で行うことができる。 値のキャストを担う機能をどこで行うか考えたところ、serializerで行うことにした。
複雑なデータのやりくりであればserializerでやるべきではないのだが、今回のようなシンプルな値の変換はserializer内のto_internal_valueで行うのが最適という結論に至った。 理由としては、2のメソッドはserializerのバリデーション実行前、書き込み時のみに実行されるからだ。 また、serializerの持つfieldを扱うことができるので楽だなと。 ということで、以下のようにコードを実装した。
class User(ModelSerializer): class Meta: model = User fields = "__all__" def to_internal_value(self, data): cast_blank_fields = ["non_blank_field"] fields = self._writable_fields for field in fields: field_name = field.field_name if field_name in cast_blank_fields: if not field.get_value(data): data[field_name] = "" return super().to_internal_value(data)
上記のように、to_internal_valueをオバーライドしつつ、そのベースクラスの同メソッドを呼ぶことで、上書きしたあとにもベースクラスのバリデーションも実行できるという手段である。