読者です 読者をやめる 読者になる 読者になる

らっちゃいブログ

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

Django REST framework 超入門

django rest_framework python

スポンサーリンク

今回は Django で rest な API を実装するのに超絶便利な Django REST framework を紹介します。

その名の通り、Django で RESTful な API を作るための framework になります。

APIの開発効率が何倍にも上がる代物ですので、ぜひみなさまにも使っていただきたいと思っています。

はじめに

前回作成した racchai プロジェクトをベースに進めていきます。

racchai.hatenablog.com

まずは rest_framework のインストールから。

$ pip install djangorestframework
$ pip install markdown
$ pip install django-filter

次は racchai/settings.py の INSTALLED_APPS に rest_framework を追記します。

# Application definition

INSTALLED_APPS = ( 
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'racchai',
+   'rest_framework',
)

これで準備は整いました!

簡単なAPIを作ってみる

その前に、前回の記事で作成したモデル情報を改めて用意します。

$ cat > racchai/models.py <<EOF
from django.db import models

class Writer(models.Model):
    name = models.CharField(max_length=128)

class Article(models.Model):
    writer = models.ForeignKey(Writer, related_name='articles')
    title = models.CharField(max_length=512)
    contents = models.TextField()
EOF

ここまでは Django を使う場合と一緒です。

Serializer を定義する

rest_framework では、Serializer と呼ばれるモジュールを利用するシーンが多いです。

  • リクエストパラメータのバリデーションおよびフィルタリング
  • データベースへの保存
  • jsonシリアライズ

等々、用途は様々です。

Serializer を制するものが rest_framework を制します。

今回は各モデルに対応する Serializer として、ModelSerializerを継承したクラスを作成します。

$ cat > racchai/serializers.py <<EOF
from rest_framework import serializers
from racchai.models import Article, Writer

class WriterSerializer(serializers.ModelSerializer):
    class Meta:
        model = Writer

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
EOF

今回は WriterSerializer と ArticleSerializer を作成しました。

Articleを全件取得する API を作ってみよう

次は API を作成します。

viewsets.ModelViewSet を継承して、serializer_class に対応する serializer を設定します。

apis.py

$ cat > racchai/apis.py <<EOF
from rest_framework import viewsets, routers
from racchai.models import Article
from racchai.serializers import ArticleSerializer

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

router = routers.DefaultRouter()
router.register(r'articles', ArticleViewSet)
EOF

なんとこれだけで API が実装できています。

では、urls.py で実際のエンドポイントを定義しましょう。

$ cat > racchai/urls.py <<EOF
from django.conf.urls import url, include
from racchai import apis

urlpatterns = [
    url(r'^api/', include(apis.router.urls)),
]
EOF

これで準備が整いました。一瞬でしたね。

それでは開発サーバーを起動して、Article一覧を取得してみます。

$ ./manage.py runserver
$ curl http://localhost:8000/api/articles.json
[{"id":1,"title":"title1","contents":"contents1","writer":1},{"id":2,"title":"title2","contents":"contents2","writer":1}]

無事Article情報が取得できました!

前回の記事では Django 組み込みの JSONリアライザを利用しましたが、非常にクセの強い JSON が生成されてしまいました。

rest_framework を使えば納得(普通)の出力結果を得ることができます。

API 経由でArticleを作成してみよう

実は、viewsets.ModelViewSet を継承した時点で、レコード取得・作成・更新・削除までできるようになっています。

API 経由でデータを登録するには、POST を使います。

$ curl -X POST http://localhost:8888/api/articles.json -d "writer=1&title=hoge&contents=fuga"
{"id":4,"title":"hoge","contents":"fuga","writer":1}

なんか登録されてるっぽいですね!

再度全件取得してみましょう。

$ curl http://localhost:8000/api/articles.json
[{"id":1,"title":"title1","contents":"contents1","writer":1},{"id":2,"title":"title2","contents":"contents2","writer":1},{"id":3,"title":"hoge","contents":"fuga","writer":1}]

新たに登録されたレコードが取得できているのがわかりますね。

Serializer の機能いろいろ

特定のフィールドは出力したくない

ありますよね。ユーザーのパスワードフィールドとかは画面には表示しない、とか。

出力対象のフィールドは Serializer クラス内で制限することができます。

手段はいくつかありますが、今回は writer フィールドを書き込み専用フィールドとして上書きする方法で実現してみます。

class ArticleSerializer(serializers.ModelSerializer):
+   writer = serializers.IntegerField(write_only=True)
    class Meta:
        model = Article

上のようにArticleSerializerに一行足して、レコード情報を取得してみましょう。

$ curl http://localhost:8000/api/articles/3.json
{"id":3,"title":"hoge","contents":"fuga"}

無事、writer が表示されなくなりました。

外部キー参照先はキー値じゃなくてオブジェクトとして取得したい

今回でいう、writer はオブジェクトで取得したい!ということですが、これも簡単に実現が可能です。

class ArticleSerializer(serializers.ModelSerializer):
+   writer = WriterSerializer()
    class Meta:
        model = Article

writer フィールドを WriterSerializer で上書きしてしまうだけです。

それでは確認してみます。

$ curl http://localhost:8000/api/articles/3.json
{"id":3,"writer":{"id":1,"name":"racchai"},"title":"hoge","contents":"fuga"}

無事参照先レコードもオブジェクトとして取得できてますね。

外部キー参照先も同時に作成したい

参照がオブジェクトで取得できるなら、作成も同様にオブジェクト形式で送信したいですよね。

もちろん可能です。

ArticleSerializerを以下のように編集しましょう。

class ArticleSerializer(serializers.ModelSerializer):
    writer = WriterSerializer()
    class Meta:
        model = Article

+   def create(self, validated_data):
+       writer = Writer(**validated_data.pop('writer'))
+       writer.save()
+       return super(ArticleSerializer, self).create(dict(validated_data, **{'writer': writer}))

やってることとしては、デフォルトの create 動作前に Writer を作成してるだけです。

では登録してみましょう。

今回はリクエストデータ自体も JSON にしてみます。

$ curl http://localhost:8000/api/articles.json -X POST -d "{\"writer\":{\"name\":\"new writer\"},\"title\":\"aaa\",\"contents\":\"bbb\"}" -H "Content-Type: application/json"                                      │
{"id":4,"writer":{"id":2,"name":"new writer"},"title":"aaa","contents":"bbb"}

登録できてそうですね!

念のため登録したArticleを取得してみます。

$ curl http://localhost:8888/api/articles/4.json
{"id":4,"writer":{"id":2,"name":"new writer"},"title":"aaa","contents":"bbb"}

作成時のレスポンスと同様のデータが取得できました。

まとめ

以上、簡単に Django REST framework について紹介してみました。

細かく解説できていない点も多いですが、簡単に API を実装できるイメージは伝わったかと思います。

本記事ではほんのさわりだけ紹介しましたが、まだまだいろんな機能が隠されています。

これからも、本ブログでは Django REST framework のノウハウについて紹介していきますので、お楽しみに!