Django REST framework (DRF)で API のバリデーションを実装します。
Django のバリデーションはフォームの役割ですが、DRF のバリデーションはシリアライザの役割です。記述方法は違いますが、実装方法は似ているので、Django のバリデーションに慣れている人は、DRF のバリデーション実装方法もすぐに慣れると思います。
実装イメージ
環境とバージョン
- CentOS 7.4
- Python 3.6.4
- Django 2.0.3
- Django REST framework 3.8.2
インストール
Python
$ sudo yum install -y https://centos7.iuscommunity.org/ius-release.rpm $ sudo yum install -y python36u python36u-libs python36u-devel python36u-pip
Python は IUS リポジトリの Python 3.6 をインストールします。CentOS 7 で Python3 を使う方法として、SCL もありますが、コマンドやパスが複雑になるので、私は、IUS リポジトリの Python を使います。
Django
$ sudo pip install django
Django をインストールします。
Django REST framework
$ sudo pip install djangorestframework
Django REST framework をインストールします。
実装
startproject, startapp
$ django-admin startproject drf_validation $ cd drf_validation/ $ python3.6 manage.py startapp app
Django のコマンドを使って、プロジェクトの雛形を生成します。
settings.py
... ALLOWED_HOSTS = ['*'] INSTALLED_APPS = [ ... 'rest_framework', 'app.apps.AppConfig', ] ...
雛形で生成した settings.py を修正していきます。
外部からのアクセスを許可するために、ALLOWED_HOSTS に ‘*’ をセットし、INSTALLED_APPS に先ほど、生成したアプリケーション app と、Django REST framework の rest_framework を追加します。
serializers.py
from django.contrib.auth.models import User from rest_framework import serializers class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = '__all__' def validate_username(self, username): if 'hoge' in username.lower(): raise serializers.ValidationError('The username `hoge` can not be used.') return username def validate(self, data): if 'hoge' in data['first_name'].lower() and 'fuga' in data['last_name'].lower(): raise serializers.ValidationError('The first name `hoge` and last name `fuga` can not be used.') return data
シリアライザ serializers.py を作成し、バリデーションを実装します。通常の Django だとフォームでやるやつですね。
上記の例では、Django の認証用モデル User に対しバリデーション処理を実装しています。
- ユーザ名 hoge の場合はエラー
- ファーストネームが hoge かつ、ラストネームが fuga の場合はエラー
フィールド単位のバリデーションは、validation_フィールド名関数で、フィールドの組み合わせでバリデーションしたい場合は、validation 関数で実装します。通常の Django のフォームの clean と一緒ですね。
ここで ValidationError で raise すると、レスポンスが HTTP 400 Bad Request になります。
views.py
from django.contrib.auth.models import User from rest_framework import viewsets from app.serializers import UserSerializer class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all().order_by('-date_joined') serializer_class = UserSerializer
views.py です。DRF デフォルトの動作を変えたい場合は、ここで、該当する関数をオーバーライドすることで実現することができます。
urls.py
from django.urls import path, include from rest_framework import routers from app import views router = routers.DefaultRouter() router.register('user', views.UserViewSet) urlpatterns = [ path('api/', include(router.urls)), ]
urls.py で URL と view をマッピングします。
tree
$ tree . ├── app │ ├── __init__.py │ ├── apps.py │ ├── serializers.py │ └── views.py ├── drf_validation │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── manage.py 2 directories, 9 files
ファイル構成はこのようになりました。
動作確認
DB migrate
$ python3.6 manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying sessions.0001_initial... OK
Django 認証用のモデルを使用しますので、DB migrate をします。
runserver
$ python3.6 manage.py runserver 0.0.0.0:8000
動作確認のため、Django デバッグサーバの runserver を起動します。
POST /api/user/
http://IPアドレス:8000/api/user/ にアクセスすると、入力フォームのページが出てきますので、そこでバリデーションの動作を確認することができます。
まとめ
Django REST framework で API のバリデーションを実装しました。
通常の Django のバリデーションと同じように実装できるので、簡単に実装することができましたね。