投稿日: | 最終更新日:
【API】DRFのバリデーションのやり方【Django】
DRFのシリアライザを利用し、バリデーションを行います。
DRFでバリデーションをするには?
シリアライザを使うことで、Django入力フォームと同じように入力情報のバリデーションをおこなうことができます。
- ①検証対象の入力データを引数dataに渡します。
- ②シリアライザをインスタンス化します。
- ③「is_valid()」を実行することで入力データのバリデーションをおこなうことができます。
バリデーションの対象フィールド
バリデーションの対象となるのは次のフィールドです。
登録・更新 | すべての入力用(つまり read_only=True ではない)フィールド |
---|---|
一部更新 | 引数dataに含まれるすべての入力用(read_only=True ではない) フィールド |
モデルのフィールドオプションで 「editable=False」が指定されているフィールドは「read_only=True」 になるため、 バリデーションの対象外です。
バリデーションのOKとNG
バリデーションOK
is_valid() の戻り値がTrue(すなわちバリデーション OK)の場合、 シリアライザオブジェクトの 「validated_data」 という属性にアクセスすることで、 バリデーション済みの値が保持された「OrderedDict型」のオブジェクトを取得することができます。
from api.serializers import BookSerializer serializer = BookSerializer(data={'title': 'DRFの本', 'price': 1500}) serializer.is_valid() >>True serializer.validated_data OrderedDict([('title', 'DRFの本'), ('price', 1500)]) serializer.errors >>{}
バリデーションNG
バリデーションNGの場合は、「errors」という属性です。
フィールド名とエラーの詳細を保持した「OrderedDict型」のオブジェクトを取得することができます。 この場合、「validated_data」 は空の dictになるので注意が必要です。IntegerFieldの「price」に「aaa」という文字列を入れると、is_valid() の戻り値はFalse になります。
serializer = BookSerializer(data={'title': 'DRFの本', 'price': 'aaa'}) serializer.is_valid() >>False serializer.errors >>{'price': [ErrorDetail(string='有効な整数を入力してください。', code='invalid')]} serializer.validated_data >>{}
また次のように raise_exception=True を指定して is_valid() を実行すると、 バリデーションNGの場合「rest_framework.exceptions.ValidationError」がraiseされます。後述する汎用APIViewやModelViewSetでは、この仕組みを利用してバリデーションNG時のエラーメッセージを伝播しています。
serializer = BookSerializer(data={'title': 'DRFの本', 'price': 'aaa'}) serializer.is_valid(raise_exception=True) >>Traceback (most recent call last): >>... (略)... >>raise ValidationError(self.errors) >>rest_framework.exceptions.ValidationError: {'price': [ErrorDetail(string='有効な 整数を入力してください。', code='invalid')]}
ところで、 is_valid() が実行されると、 シリアライザとそのフィールドに定義されたバ リデーションメソッドが、 決まった順序で次々 と実行されます。
シリアライザのバリデーションフロー
①シリアライザの「run_validation()」が呼ばれます。
②その中で、 シリアライザに定義した入力用フィールドの「run_validation()」が呼び出されます。
フィールドの「run_validation()」では、フィールドの種類に応じた文字種チェックなどのデフォルトのバリデーションのほか、 フィールドのvalidators属性に定義したバリデーションが実行されます。
③フィールドがシリアライザの場合、再帰的に run_validation() が実行されていきます。
④シリアライザに 「validate_<フィールド名>」 というメソッドが定義されている場合、それが実行されます。
ここまでが、 バリデーション対象のフィールドの数だけ繰り返されます。
バリデーションが全てOK
シリアライザ自身の「run_validators()」が呼ばれてMetaクラスの「validators」に定義されたバリデーションが実行されます。 ここまでのバリデーションがすべてOKの場合、最後にvalidate()メソッドが呼ばれます。
これらはいずれも、複数フィールド間のバリデーションを行うためです。
バリデーションの追加方法
ModelSerializer や Serializerを継承したシリアライザにバリデーションを追加する方法としては、以下の4つほどが挙げられます。
- 1.Meta クラスの extra_kwargs に validators を追加
- 2.validate_<フィールド名>() メソッドを追加
- 3.Meta クラスの validators に追加
- 4.validate() メソッドを追加
1.と 2.が実行された後に3.が実行され、 最後に4.が実行されます。1.および2.は単体のフィールドに対するバリデーションです。
これらのバリデーションは、「read_only=True」のフィールド、 および一部更新の場合で入力データに含まれていないフィールドに対しては実行されません。
3. および 4.では複数フィールド間の相関チェックなど単体のフィールドに紐付かないバリデーションを行います。
3.は 1.と2.のバリデーションが OK になっていないと実行されません。
4.も同様に 1. から 3. までのバリデーションが OK でないと実行されません。なお、Serializer を継承したシリアライザでは、1.の方法は利用できません。
以下の例は、 シリアライザクラスに1.~4.までのバリデーションを加えたサンプルコードです。
from django.core.validators import RegexValidator from rest_framework import serializers from rest_framework.validators import UniqueTogetherValidator from .models import Book class BookSerializer(serializers.ModelSerializer): class Meta: model = Book exclude = ['created_at'] validators = [ #タイトルと価格でユニークになっていることを検証 UniqueTogetherValidator(queryset=Book.objects.all(), fields=('title', 'price'), message="タイトルと価格でユニークになっていなければいけません。 " ), ] extra_kwargs = { 'title': { 'validators': [ RegexValidator( r'^D.+$', message="タイトルは 「D」 で始めてください。"), ], }, } def validate_title(self, value): """タイトルに対するバリデーションメソッド""" if 'Java' in value: raise serializers.ValidationError( "タイトルには 「Java」 を含めないでください。") return value def validate(self, data): """複数フィールド間のバリデーションメソッド""" title = data.get('title') price = data.get('price') if title and '薄い本' in title and price and price > 3000: raise serializers.ValidationError( "薄い本は3,000円を超えてはいけません。") return data 1. や 3. の validators
ここで、シリアライザを使ったViewに以下の入力データをPOSTで送信します。
{ "title":"Javaの薄い本", "price":"aaa" }
以下のようなJsonレスポンスが返信されます。
{ "title":["タイトルは「D」で始めてください。"], "price":["有効な整数を入力してください。"] }
次回
工事中。
- Python 114
- 制作 54
- RaspberryPi 41
- Django 40
- WordPress 40
- Linux 27
- VPS 22
- JavaScript 21
- PHP 20
- HTML・CSS 19
- AWS 16
- 仮想環境 15
- レスポンシブデザイン 13
- マイコン 11
- WEB全般 11
- 動画製作 9
- Webサービス 8
- 統合開発環境 8
- 機械学習 8
- PyCharm 7
- jQuery 7
- AfterEffects 7
- 起業・設立 7
- Django REST framework 6
- C# 6
- デザイン 6
- SEO 6
- pydata 6
- Visual Studio 5
- 数学 5
- 携帯サイト 5
- heroku 5
- Mac 5
- illustrator 5
- node.js 5
- Anaconda 5
- Nginx 4
- Jupyter Notebook 4
- インフラ 4
- Google Colaboratory 4
- symfony 4
- Webスクレイピング 3
- photoshop 3
- Go言語 3
- PC 3
- ツール 3
- Docker 3
- facebook 3
- 作業効率化 3
- データベース 3
- Cloud9 3
- コマンド 2
- micro:bit 2
- Kali Linux 2
- Webサーバー 2
- MariaDB 2
- ドローン 2
- コンテナ 2
- DaVinci Resolve 2
- ネットワーク 2
- Java 2
- movie 2
- PCDJ 2
- 音楽 2
- XSERVER 2
- Ansible 1
- Vue.js 1
- JSON 1
- Bootstrap 1
- バージョン管理システム 1
- SSL 1
- S3 1
- ムームードメイン 1
- ネットワーク 1
- アニメーション 1
- D3.js 1
- Rhino 1
- アニメ 1
- git 1
- windows 1
- アクセス解析 1
- スマートフォン 1
- アフィリエイトノウハウ 1
- 知識 1
- TypeScript 1
- 役立つ本・書籍 1
- データサイエンス 1
- ESP32 1
- AI 1
- ownCloud 1
- API 1