らっちゃいブログ

日々の学びと気づきを発信するブログ

Django REST framework でバリデーションしてみよう

スポンサーリンク

みなさんお待ちかねの Django REST framework シリーズです。

バリデーションって大事なんだけど仕組みを作るのって地味にめんどくさいですよね。

Django REST framework ではそこそこ簡単に書けるようになってますので、ご紹介します。

事前準備

まずは簡単にプロジェクトを作成します。

詳しい手順と説明はこちらの記事をご参照ください。

racchai.hatenablog.com

ではプロジェクトを作成します。

$ django-admin startproject racchai
$ cd racchai

Serializer クラスを作成する

前回の記事でも触れましたが、バリデーションは Serializer を使用して実現します。

簡単な Serializer を用意しましたので、作成しましょう。

$ cat > racchai/serializers.py <<EOF
from rest_framework import serializers

class SimpleValidationSerializer(serializers.Serializer):
    integer= serializers.IntegerField()
EOF

これだけで、string フィールドは必須で、文字列のみというバリデーションができるSerializerが作成できました。

検証してみる

インタラクティブコンソールで検証してみましょう。

$ ./manage.py shell
>>> from racchai.serializers import SimpleValidationSerializer
>>> s = SimpleValidationSerializer(data={'integer': 1})
>>> s.is_valid()
True

string に文字列を指定すると、もちろん True となります。

次は 空データで試してみましょう。

>>> s = SimpleValidationSerializer(data={})
>>> s.is_valid()
False

今度は失敗しました。バリデーションが実行されていそうですね。

バリデーションメッセージを取得する

バリデーションに失敗したら、バリデーションメッセージを取得してみましょう。

>>> s = SimpleValidationSerializer(data={})
>>> s.is_valid()
False
>>> s.errors
{'integer': [u'This field is required.']}

integer フィールドが指定されていないことが原因だということがわかりますね。

試しに文字列を指定した場合のメッセージも見てみましょう。

>>> s = SimpleValidationSerializer(data={'integer': 'str'})
>>> s.is_valid()
False
>>> s.errors
{'integer': [u'A valid integer is required.']}

ちゃんと数値でない値を指定したことが原因であることがわかります。

バリデーションメッセージをカスタマイズする

バリデーションメッセージは自前で用意することが多いですよね。

今回はシンプルに Serializer 内でメッセージを差し替える方法を紹介します。

SimpleValidationSerializer を以下のように変更してみましょう。

class SimpleValidationSerializer(serializers.Serializer):
    integer= serializers.IntegerField(error_messages={'required': 'racchai!'})

ではバリデーションエラーを表示してみます。

>>> from racchai.serializers import SimpleValidationSerializer
>>> s = SimpleValidationSerializer(data={})
>>> s.is_valid()
False
>>> s.errors
{'integer': ['racchai!']}

racchai!

成功です。

意図しないデータをフィルタリングする

バリデーションを通過したら、その結果のデータを取得することになります。

その際、Serializer は自身に定義されていないパラメータを除去してくれるようになっています。

試しに、不要なデータをバリデーションにかけてみます。

>>> s = SimpleValidationSerializer(data={'integer': 1, 'not_defined': 1})
>>> s.is_valid()
True
>>> s.validated_data
OrderedDict([(u'integer', 1)])

ちゃんと not_defined が除去されて、Serializer で定義されたフィールドだけが取得できましたね。

ちなみに、validated_datais_valid を呼び出した後でないとアクセスできません。

でないと以下のようなエラーになります。

AssertionError: You must call `.is_valid()` before accessing `.validated_data`.

エラーメッセージを読めばすぐ原因がわかるものではありますが、このエラーを見て困惑する人は多い気はしますね。

おまけ

is_valid 関数には、raise_exception=True を与えることで erorrs 情報をラップした ValidationError を投げてくれる機能がついています。

>>> s = SimpleValidationSerializer(data={'integer': 'str'})
>>> s.is_valid(raise_exception=True)
ValidationError: {'integer': [u'A valid integer is required.']}

自分で API を実装するときは、楽なのでこの方法を使うことにしています。

最後に

いかがでしたでしょうか。

シンプルな設計なので、わかってしまえば直観的にサクサク実装を進められそうですね。

今回はカスタムバリデーターを作成する方法については触れませんでしたが、近いうちにご紹介できればと思います。

それではまた!