Edited at

Django REST Framework の使い方メモ

学習履歴


■はじめに

Django REST framework を使って、REST API の作成方法を学んでみる。


■環境

Mac

Python3.7

pipenv

Django2.1

Pycharm


■Library API の構築

サンプルとして、Library API を作りつつ、Django REST Framework を学んで行こう。

ただ、Django REST framework だけでは Web API を構築することができないので、

まずは、Django のアプリケーションを作り、その後、 REST framework を追加する。


■ Djangoプロジェクトの作成

pipenv を使って、仮想環境を構築して、そこに Django をインストールする。


terminal

$ mkdir django_rest_framework

$ cd django_rest_framework/
$ mkdir code
$ cd code/
$ pwd
/Users/hoge/Desktop/django_rest_framework/code

# Django をインストール
$ pipenv install django==2.1
# 仮想環境に入る
$ pipenv shell
(code-V3vlQwAZ) bash-3.2$

# Django のプロジェクトを作成
# . は、必ず必要
(code-V3vlQwAZ) bash-3.2$ django-admin startproject library_project .
(code-V3vlQwAZ) bash-3.2$ tree
.
├── Pipfile
├── Pipfile.lock
├── library_project
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py

# マイグレーションを実行
(code-V3vlQwAZ) bash-3.2$ python manage.py migrate

# ローカルサーバを起動
(code-V3vlQwAZ) bash-3.2$ python manage.py runserver


ここまで作業できたら、localhost:8000 にアクセスしてみる。

スクリーンショット 2018-09-23 11.46.49.png


■ アプリケーションの追加

Ctrl + c でローカルサーバーを止めて、アプリケーションを追加する。


terminal

# アプリケーションを追加

(code-V3vlQwAZ) bash-3.2$ python manage.py startapp books
(code-V3vlQwAZ) bash-3.2$ tree
.
├── Pipfile
├── Pipfile.lock
├── books
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── db.sqlite3
├── library_project
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py


■ アプリケーションの設定

books アプリケーションを追加できたら、いくつか設定を行う必要がある。

最初に settings.py に books アプリケーションを追加する。


library_project/settings.py

INSTALLED_APPS = [

# Local
'books.apps.BooksConfig', # 追加

'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]

それからこの変更をデータベースに反映させるために migrate を行う。


terminal

(code-V3vlQwAZ) $ python manage.py migrate


books アプリには、view, url, そしてテンプレートファイルが必要になるので、この後作成する。


■ Modelの作成

Django では、データベースの元となるデータを Model という形で作成する。


books/models.py

from django.db import models

class Book(models.Model):
title = models.CharField(max_length=250)
subtitle = models.CharField(max_length=250)
author = models.CharField(max_length=100)
isbn = models.CharField(max_length=13)

def __str__(self):
return self.title


続いて、マイグレーションを行う。


terminal

(code-V3vlQwAZ) $ python manage.py makemigrations books

(code-V3vlQwAZ) $ python manage.py migrate


■ 管理者の作成

続いて、Django の管理者の作成を行う。


terminal

(code-V3vlQwAZ) $ python manage.py createsuperuser

Username (leave blank to use 'hono'): admin
Email address:
Password:
Password (again):
This password is too short. It must contain at least 8 characters.
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

管理者を作成すると管理者用のページにアクセスできるようになるが、デフォルトでは books アプリが

表示されない。

表示するには、以下の設定を行う。


books/admin.py

from django.contrib import admin

from .models import Book

admin.site.register(Book)


設定が完了したら python manage.py runserver を実行して、localhost:8000/admin にアクセスしてみよう。

スクリーンショット 2018-09-23 16.45.19.png

スクリーンショット 2018-09-23 16.45.56.png

管理者用ページに Books アプリが登録されていることがわかる。

Books アプリに適当にデータを入れてみよう。

スクリーンショット 2018-09-23 16.47.49.png

SAVE ボタンを押下するとデータが登録される。

スクリーンショット 2018-09-23 16.48.44.png

管理者ページを作成し、データの登録までできるようになった。

続いて、Veiw を作成しよう。


■ View の作成

views.py にて、データベースの Model をどのように画面に表示するかコントロールすることができる。

ここでは、Django の組み込み関数の ListView を使ってみよう。


books/views.py

from django.views.generic import ListView

from .models import Book

class BookListView(ListView):
model = Book
template_name = 'book_list.html'


BookListView クラスでは、Book Model と book_list.html テンプレート(これから作成する)を使用する設定をしている。

return 文とか設定しなくても ListView を継承することで、データを受け渡しできるらしい。

あとは、url と テンプレートを作成する必要がある。


■ URLs の作成

プロジェクトレベルの urls.py に book アプリへ繋がるパスを記述する必要がある。


library_project/urls.py

from django.contrib import admin

from django.urls import path, include # 追加

urlpatterns = [
path('admin/', admin.site.urls),
path('', include('books.urls')), # 追加
]

次に アプリレベルの urls.py を作成する。


terminal

(code-V3vlQwAZ) $ touch books/urls.py


ここに、book アプリの view へのパスを記述する。


books/urls.py

from django.urls import path

from .views import BookListView

urlpatterns = [
path('', BookListView.as_view(), name='home')
]


最後にテンプレートを作成する。


■テンプレートの作成

テンプレートファイルは、book ディレクトリ配下に作成する。

(code-V3vlQwAZ) $ mkdir books/templates

(code-V3vlQwAZ) $ mkdir books/templates/books
(code-V3vlQwAZ) $ touch books/templates/books/book_list.html
(code-V3vlQwAZ) $ tree books
books
├── __init__.py
├── __pycache__
│   ├── __init__.cpython-37.pyc
│   ├── admin.cpython-37.pyc
│   ├── apps.cpython-37.pyc
│   └── models.cpython-37.pyc
├── admin.py
├── apps.py
├── migrations
│   ├── 0001_initial.py
│   ├── __init__.py
│   └── __pycache__
│   ├── 0001_initial.cpython-37.pyc
│   └── __init__.cpython-37.pyc
├── models.py
├── templates
│   └── books
│   └── book_list.html
├── tests.py
├── urls.py
└── views.py

book_list.html にて、 View から渡されたデータを「こう表示しますよ」みたいな設定をする。


books/templates/books/book_list.html

<h1>All books</h1>

{% for book in object_list %}
<ul>
<li>Title: {{ book.title }}</li>
<li>Subtitle: {{ book.subtitle }}</li>
<li>Author: {{ book.author }}</li>
<li>ISBN: {{ book.isbn }}</li>
</ul>
{% endfor %}

for タグは、Django の template language というやつで、他にも色々な種類がある。

ListView のオブジェクトである object_list には、Books モデルの全てのデータが格納されているので、for タグで

画面上に全て表示するようにしている。

ここまでできたら画面上に Model の中身を表示できるようになっているはずだ。

python manage.py runserver でローカルサーバを起動し、localhost:8000 にアクセスする。

スクリーンショット 2018-09-23 18.43.09.png

うまくいったので、いよいよ Django REST Framework を導入してみよう。


■ Django REST Framework の導入

Django REST Framework は、Django のサードパーティアプリとして追加する。

ローカルサーバが起動している場合は、Ctrl + c で一旦停止してから、以下のコマンドを実行する。


terminal

(code-V3vlQwAZ) $ pipenv install djangorestframework==3.8.2


コマンド実行後、このフレームワークをアプリとして、Django に登録する。


library_project/settings.py

INSTALLED_APPS = [

# Local
'books.apps.BooksConfig',

# 3rd party
'rest_framework', # 追加

'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]


次は、専用の api アプリを作成する。


terminal

(code-V3vlQwAZ) $ python manage.py startapp api


これも Django にアプリとして認識させる。


library_project/settings.py

INSTALLED_APPS = [

# Local
'books.apps.BooksConfig',
'api.apps.ApiConfig', # 追加

# 3rd party
'rest_framework',

'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]


この api アプリは、専用のデータベースを持たないので、migration は不要である。

次に、url の設定を行う。(流れは、bookアプリの時と一緒)


library_project/urls.py

from django.contrib import admin

from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('', include('books.urls')),
path('api/', include('api.urls')), # 追加
]



terminal

(code-V3vlQwAZ) $ touch api/urls.py



api/urls.py

from django.urls import path

from .views import BookAPIView

urlpatterns = [
path('', BookAPIView.as_view()),
]


次は、view の設定をする。


api/views.py

from rest_framework import generics

from books.models import Book
from .serializers import BookSerializer

class BookAPIView(generics.ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer


ListAPIView を継承したクラスを作成するとBook Model に対して、読み取り専用のエンドポイントを

提供できるようになるらしい。

Serializer は、Django のモデルデータを JSON 形式に変換して処理できるようにするためのもので、これから作成する。


terminal

(code-V3vlQwAZ) $ touch api/serializers.py



api/serializers.py

from rest_framework import serializers

from books.models import Book

class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('title', 'subtitle', 'author', 'isbn')



■ 動作確認

設定は全て完了したので、動作確認をしてみよう。


terminal

(code-V3vlQwAZ) $ python manage.py runserver


別のターミナルを立ち上げて、以下のコマンドを実行する。


terminal

(code-V3vlQwAZ) $ curl http://127.0.0.1:8000/api/

[{"title":"Django for Beginners","subtitle":"Build websites with Python and Django","author":"Rarara O. Tomas","isbn":"234-156789767"}]

うまくデータを取得できているようだ。

http://localhost:8000/api/ にブラウザからアクセスしてみよう。

スクリーンショット 2018-09-23 19.16.16.png

Django REST Framework ではこのような画面をデフォルトで提供してくれる。


■Todo API の構築

さて、今度は、Todo リストの API を作ってみよう。

今度は、back-end 側を Django で、front-end 側を React で実装してみる。

*前回の pipenv の仮想環境からは、deactivate or exit で抜けておくこと


terminal

$ mkdir todo && cd todo/

$ mkdir backend && cd backend
$ pipenv install django==2.1
$ pipenv shell
(backend-zfnLEadP) bash-3.2$ django-admin startproject todo_project .
(backend-zfnLEadP) bash-3.2$ python manage.py startapp todos
(backend-zfnLEadP) bash-3.2$ python manage.py migrate
(backend-zfnLEadP) bash-3.2$ tree
.
├── Pipfile
├── Pipfile.lock
├── db.sqlite3
├── manage.py
├── todo_project
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── todos
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

Work ディレクトリの作成から Django のアプリケーションを作成するところまで一気に行った。


todo_project/settings.py

INSTALLED_APPS = [

# Local
'todos.apps.TodosConfig',

'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]


ローカルサーバを起動し、localhost:8000/ にアクセスして、Django が起動しているか確認しよう。


terminal

(backend-zfnLEadP) bash-3.2$ python manage.py runserver


スクリーンショット 2018-09-24 7.06.27.png


■ Model の作成

次は、Todo API の Model を作成する。


todos/models.py

from django.db import models

class Todo(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()

def __str__(self):
return self.title


Model を作ったら Ctrl + c でローカルサーバを停止し、以下のコマンドを実行する。


terminal

(backend-zfnLEadP) bash-3.2$ python manage.py makemigrations todos

(backend-zfnLEadP) bash-3.2$ python manage.py migrate


■ 管理者ページの設定

管理者ページも設定しておこう。


todos/admin.py

from django.contrib import admin

from .models import Todo

admin.site.register(Todo)


管理者も作成する。


terminal

(backend-zfnLEadP) bash-3.2$ python manage.py createsuperuser

Username (leave blank to use 'hono'): admin
Email address:
Password:
Password (again):
This password is too short. It must contain at least 8 characters.
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

ローカルサーバを起動して、localhost:8000/admin にアクセスしてみる。

スクリーンショット 2018-09-24 7.16.59.png

管理者ページは、問題なく作成されているようだ。

Todo の "+ Add" を押下して、アイテムを 3 つ追加する。

スクリーンショット 2018-09-24 7.19.16.png


■ Django REST Framework の追加

Control + c で、ローカルサーバを停止し、Django REST Framework をインストールする。


terminal

(backend-zfnLEadP) bash-3.2$ pipenv install djangorestframework==3.8.2


Django REST Framework をインストールしたら、settings.py の設定を行う。


todo_project/settings.py

INSTALLED_APPS = [

# Local
'todos.apps.TodosConfig',

# 3rd party
'rest_framework',

'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]

# Setting permission
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
]
}


Django REST Framework への設定は、Django の settings.py ファイル内に記述するらしい。

上記以外にも[様々な設定]があるみたいだ。


■ ルーティングの設定

ユーザのアクセスポイントを設定する。

まずは、プロジェクトレベルの urls.py を設定する。


todo_project/urls.py

from django.contrib import admin

from django.urls import include, path

urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('todos.urls')),
]


次に、以下のコマンドで、アプリレベルの urls.py を作成する。


terminal

(backend-zfnLEadP) bash-3.2$ touch todos/urls.py


ここに、views へのパスを記述する。


todos/urls.py

from django.urls import path

from .views import ListTodo, DetailTodo

urlpatterns = [
path('<int:pk>/', DetailTodo.as_view()),
path('', ListTodo.as_view()),
]


ListTodo と DetailTodo は、この後、views.py に設定する。

ルーティングの設定は、以上だ。


■ シリアライズ化

Django 上のデータの実態は、Model だ。(この表現が正しいのかさておき)

Djang REST Framework 場で、データをやり取りする際は、JSON 形式等に変換してからやり取りする

必要があるらしいので、データのシリアライズ化が必要になる。

Model -> JSON

まずは、以下のファイルを作成する。


terminal

(backend-zfnLEadP) bash-3.2$ touch todos/serializers.py


作成したファイルに対して、以下の設定を行う。


todos/serializers.py

from rest_framework import serializers

from .models import Todo

class TodoSerializer(serializers.ModelSerializer):
class Meta:
model = Todo
fields = ('id', 'title', 'body',)



■ views の設定

views.py では、テンプレートへどのような形でデータを送信するか定義できる。


todos/views.py

from rest_framework import generics

from .models import Todo
from .serializers import TodoSerializer

class ListTodo(generics.ListAPIView):
queryset = Todo.objects.all()
serializer_class = TodoSerializer

class DetailTodo(generics.RetrieveAPIView):
queryset = Todo.objects.all()
serializer_class = TodoSerializer


Viewの設定として、ListAPIView は、Todo アプリの全てのモデルデータを表示し、RetrieveAPIView は、

モデルデータの一つを表示する仕組みを提供するらしい。


■ 動作確認

ここまで設定できたら動作確認をしてみよう。

ローカルサーバを起動する。


terminal

(backend-zfnLEadP) bash-3.2$ python manage.py runserver


localhost:8000/api/ にアクセスして、データが表示できるか確認してみよう。

スクリーンショット 2018-09-24 18.52.51.png

ListAPIView のおかげで、Todo アプリの全てのアイテムが表示されている。

今度は、localhost:8000/api/1 にアクセスしてみよう。

スクリーンショット 2018-09-24 18.56.01.png

api/1 の 1 は、モデルデータを追加するとき Django が自動で生成してくれる primary key だ。

アプリ側の settings.py に <int:pk> と設定している 


■ CORS

Cross-Origin Resource Shareing(CORS)は、異なるドメイン間(localhost:3000 <----> localhost:8000>で動作する

アプリケーション同士がリソースを共有できるようにする仕組みらしい。

backend を Django で、frontend を React での実装を試みようとしているが、これらのアプリケーションがリソースを

共有できるようにしたい。(ここで言うリソースとは、Django の todo Model のこと)

CORS を実現するには、http 通信に CORS ヘッダーを含める必要があるらしい。

django-cors-headersを使用すると最小限のコーディングで、実装が行えるようだ。

(backend-zfnLEadP) bash-3.2$ pipenv install django-cors-headers==2.4.0

追加したら以下の 3 つのことを行う。


  1. INSTALLED_APPS に corsheaders を追加

  2. 指定の middleware を 2 つ追加

  3. CORS_ORIGIN_WHITELIST を作成

これらは、setting.py 場で設定する。


todo_project/settings.py

INSTALLED_APPS = [

# Local
'todos.apps.TodosConfig',

# 3rd party
'rest_framework',
'corsheaders',# 追加

'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]

MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',# 追加
'django.middleware.common.CommonMiddleware',# 追加
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# 追加
CORS_ORIGIN_WHITELIST = (
'localhost:3000/'
)


localhost:3000 は、React のデフォルトのドメインなので上記のように設定している。


■ Reactの実装

backend 側の Django の実装は完了したので、frontend 側 の React の実装に入ろう。

React は、javascript のフレームワークの一つで、NodeJs 場で動く。

Django のローカルサーバを動作させている terminal とは別の terminal を立ち上げて、NodeJs を brew でインストールしよう。


terminal

$ brew install node

$ sudo chown -R $USER /usr/local # 必須ではない
$ brew link node # 必須ではない
$ brew link --overwrite node # 必須ではない(npmのパスを貼る)
$ npm install -g create-react-app # Reactのインストール

*必須ではないとなっているところは、筆者の環境上で必要なものだったコマンド

*事前にHomebrew をインストールしておく必要がある

npm へのパスがなかなかの貼れなくて、大変だった。

todo ディレクトリ内に React アプリを作成する。


terminal

$ pwd

/Users/hono/hoge/django_rest_framework/todo
$ create-react-app frontend
$ cd frontend
$ npm start

npm start を実行すると React の画面が表示される。

スクリーンショット 2018-09-24 22.51.46.png


■ Mockデータ

インストールした React を使って、Django の Model データを画面に表示させようとしている。

(Django はあくまで データを提供する API に徹する)

だがその前に、Mock データを使って React の画面表示のやり方を見てみよう。

編集するファイルは、frontend ディレクトリの src/App.js のみだ。


src/App.js

import React, { Component } from 'react';

// Mock データ
const list = [
{
id: 1,
title: "1st todo",
description: "Learn Django properly."
},
{
id: 2,
title: "Second item",
description: "Learn Python."
},
{
id: 3,
title: "Learn HTTP",
description: "It's important."
}
]

class App extends Component {
constructor (props) {
super(props);
this.state = { list };
}

render() {
return (
<div>
{this.state.list.map(item => (
<div key={item.id}>
<h1>{item.title}</h1>
<p>{item.description}</p>
</div>
))}
</div>
);
}
}

export default App;


list に Mock データを格納し、App コンポーネントに渡した。

それを map でループして、画面上に全てのデータを表示させる。

npm start している状態から localhost:3000 を web ブラウザで確認してみるとデータが表示されていることがわかる。

スクリーンショット 2018-09-25 6.00.37.png


■ アプリの連携(axios)

React 側の準備も整ったので、いよいよ Django と連携してみようと思う。

Django 側では、localhost:8000/api へアクセスするとデータを取得できるようにしてあるので、

ここに React 側から Get リクエストを送る必要がある。

axios を使うと REST API へのリクエスト処理を簡単に実装できるようになるらしい。

一旦、Control + c で React アプリを停止して、 axios をインストールする。


terminal

$ npm install axios

$ npm start

次は、App.js を以下のように書き換える。


src/App.js

import React, { Component } from 'react';

import axios from 'axios';

class App extends Component {
state = {
todos: []
};

componentDidMount() {
this.getTodos();
}

getTodos() {
axios
.get('http://localhost:8000/api/')
.then(res => {
this.setState({ todos: res.data });
})
.catch(err => {
console.log(err);
});
}

render() {
return (
<div>
{this.state.todos.map(item => (
<div key={item.id}>
<h1>{item.title}</h1>
<p>{item.body}</p>
</div>
))}
</div>
);
}
}

export default App;


画面を表示してみる。

スクリーンショット 2018-09-25 6.28.53.png

うまくいったようだ。


■ Blog アプリ

Django REST Framework の機能をもっと使った Blog アプリを作成する。

具体的には、管理者以外のユーザの作成、権限、CRUD(Create,Read,Update,Delete)機能など。


■ セットアップ

初期設定をしよう。


terminal

$ pwd

/Users/hoge/Desktop/django_rest_framework
$ mkdir blogapi && cd blogapi
$ pipenv install django==2.1
$ pipenv shell
(blogapi-H-RPCYMU) bash-3.2$ django-admin startproject blog_project .
(blogapi-H-RPCYMU) bash-3.2$ python manage.py startapp posts

blog プロジェクトに posts アプリを作成したので、settings.py に登録して Django に認識させる。


settings.py

INSTALLED_APPS = [

# Local
'posts.apps.PostsConfig', # 追加

'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]

次は、マイグレーションを行う。


terminal

(blogapi-H-RPCYMU) $ python manage.py migrate



■ Model の設定

次は、Model を作成する。

Post のオブジェクトとして作成するので、投稿者、タイトル、本文、作成日、修正日あたりのカラムを持っていればいいと思う。


posts/models.py

from django.db import models

from django.contrib.auth.models import User

class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=50)
body = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

def __str__(self):
return self.title


Model ができたら再びマイグレーションを行う。


terminal

(blogapi-H-RPCYMU) $ python manage.py makemigrations posts

(blogapi-H-RPCYMU) $ python manage.py migrate


■ 管理者の作成

管理者も作成しておこう。


posts/admin.py

from django.contrib import admin

from .models import Post

admin.site.register(Post)



terminal

(blogapi-H-RPCYMU) $ python manage.py createsuperuser

Username (leave blank to use 'hono'): admin
Email address:
Password:
Password (again):
Superuser created successfully.
(blogapi-H-RPCYMU) $ python manage.py runserver

localhost:8000/admin/ にアクセスして、管理者と管理者ページが作成されたか確認する。

スクリーンショット 2018-09-26 6.05.48.png

Posts の [+ Add] をクリックして、何かデータを入力して、保存しよう。

スクリーンショット 2018-09-26 6.07.58.png

スクリーンショット 2018-09-26 6.08.11.png


■ Test コード

ちょっとだけ寄り道して、Post に対し、テストコードを書いてみる。

ログインユーザが、タイトルと本文を入力して、blog post を作れるか、みたいな感じのテストにする。


posts/tests.py

from django.test import TestCase

from django.contrib.auth.models import User

from .models import Post

class BlogTests(TestCase):
@classmethod
def setUpTestData(cls):
# Create a User
testuser1 = User.objects.create_user(
username='testuser1',
password='abc123!'
)
testuser1.save()

# Create a blog post
test_post = Post.objects.create(
author=testuser1,
title='Blog title',
body='Body content...'
)
test_post.save()

def test_blog_content(self):
post = Post.objects.get(id=1)
expected_author = f'{post.author}'
expected_title = f'{post.title}'
expected_body = f'{post.body}'
self.assertEquals(expected_author, 'testuser1')
self.assertEquals(expected_title, 'Blog title')
self.assertEquals(expected_body, 'Body content...')


ローカルサーバが動いていたら Ctrl + c で一旦止めて、terminal 上から以下のコマンドを押下してテストする。

(blogapi-H-RPCYMU) $ python manage.py test

Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.125s

OK
Destroying test database for alias 'default'...

Django のテストコードは、こんな感じで書くらしい。


■ Django REST Framework

今まで見てきた通り、Django REST Framework を追加しよう。


terminal

(blogapi-H-RPCYMU) $ pipenv install djangorestframework==3.8.2


次に、settings.py を書き換える。


blog_project/settings.py

INSTALLED_APPS = [

# Local
'posts.apps.PostsConfig',

# 3rd-party apps
'rest_framework', # 追加

'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
# 追加
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
]
}



■ルーティング設定

ルーティングの設定をしよう。


blog_project/urls.py

from django.contrib import admin

from django.urls import include, path

urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('posts.urls')),
]


url の v1 は API の Version 1 を意味している。

*API として利用するので、こういう命名規則がベクトプラクティスらしい

アプリレベルの urls.py を作成し、ルーティングの設定を行う。


terminal

(blogapi-H-RPCYMU) $ touch posts/urls.py



posts/urls.py

# posts/urls.py

from django.urls import path

from .views import PostList, PostDetail

urlpatterns = [
path('<int:pk>/', PostDetail.as_view()),
path('', PostList.as_view()),
]


PostList と PostDetail は、あとで作成する。


■シリアライズ化

Model データを JSON 形式に変換する。


terminal

(blogapi-H-RPCYMU) $ touch posts/serializers.py



posts/serializers.py

from rest_framework import serializers

from .models import Post

class PostSerializer(serializers.ModelSerializer):

class Meta:
fields = ('id', 'author', 'title', 'body', 'created_at',)
model = Post



■ view の設定

view の設定をする。


posts/views.py

from rest_framework import generics

from .models import Post
from .serializers import PostSerializer

# ListCreateAPIView -> read-write endpoint
class PostList(generics.ListCreateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer

# RetrieveUpdateDestoryAPIView -> ALlows read, update, delete
class PostDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer



■ 動作確認

ここまで設定が完了したら localhost:8000/api/v1/ にアクセスして、実際の表示を確認しよう。

スクリーンショット 2018-09-28 6.13.04.png

PostList は、問題なく動作しているようだ。

localhost:8000/api/v1/1 にもアクセスする。

スクリーンショット 2018-09-28 6.14.43.png

PostDetail も問題なく動作している。


■ユーザーの追加

セキュリティは、Webサイトにとって重要なものだが、web API にとってはその 2 倍重要なものだ。(本に書いてあった)

全てのユーザーが、アイテムを作成、削除、更新、読み取りできてしまうのはよくない。

Django REST Framework では、様々なセキュリティを補佐する機能があるらしい。

テスト用にユーザーを追加しよう。

ローカルサーバを起動させて、localhost:8000/admin/ にアクセスしてから

Users で「+ Add」を押下する。

スクリーンショット 2018-09-29 5.42.22.png

testuser とパスワードを設定する。

スクリーンショット 2018-09-29 5.43.12.png

ユーザー詳細ページに遷移するが特に何も設定せずに SAVE ボタンを押下する。

スクリーンショット 2018-09-29 5.44.23.png

testuser が設定される。

スクリーンショット 2018-09-29 5.44.30.png


■ログインの実装

Django REST Framework でログイン機能を実装するのは簡単だ。

プロジェクトレベルの urls.py に以下を追加すればいい。


blog_project/urls.py

"""blog_project URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('posts.urls')),
path('api-auth/', include('rest_framework.urls')),
]


ローカルサーバを起動して、localhost:8000/api/v1/ にアクセスすると、右上に「Log in」が表示されていることがわかる。

スクリーンショット 2018-09-30 7.38.17.png


■ アクセス権限

現時点で、Web API には、AllowAny(全てのユーザーがアクセス可能)の権限が振られている。

つまり、どのユーザーでもブログの投稿、削除、読み取り、更新ができてしまう。

認証済みのユーザーのみアクセスを許可したい場合は、アクセス権限を変更すればいい。


posts/views.py

from rest_framework import generics, permissions # 追加


from .models import Post
from .serializers import PostSerializer

# ListCreateAPIView -> read-write endpoint
class PostList(generics.ListCreateAPIView): # 追加
permission_classes = (permissions.IsAuthenticated,)
queryset = Post.objects.all()
serializer_class = PostSerializer

# RetrieveUpdateDestoryAPIView -> ALlows read, update, delete
class PostDetail(generics.RetrieveUpdateDestroyAPIView): # 追加
permission_classes = (permissions.IsAuthenticated,)
queryset = Post.objects.all()
serializer_class = PostSerializer


これでログイン権限のないユーザは、何もできなくなったはずだ。

localhost:8000/api/v1/1/ にアクセスしてみる。

スクリーンショット 2018-10-01 6.08.33.png

更新するためのリストが消えている。ちなみに、ログイン済みにすると下の画像のようになる。

スクリーンショット 2018-10-01 6.10.43.png

うまくいっているようだ。

しかし、View レベルの権限だと今後、View を増やすたびに似たような権限を追加していく必要があるので、少し煩雑である。

そこで、Django REST Framework には、Project レベルでアクセス権限を設定できる仕組みが用意されている。

項目
意味

AllowAny
認証有無に関わらず、全てのユーザーはアクセス許可

IsAuthenticated
認証・登録ずみのユーザーのみアクセス許可

IsAdminUser
管理者のみアクセス許可

IsAuthenticatedOrReadOnly
未認証のユーザは、閲覧権限のみ。認証済みのユーザは、書き込み、編集、削除権限をもつ

settings.py に IsAuthenticated 権限を付与してみる。


blog_project/settings.py

REST_FRAMEWORK = {

'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}

また、views.py からさっき設定した権限を削除する。


posts/views.py

from rest_framework import generics

from .models import Post
from .serializers import PostSerializer

# ListCreateAPIView -> read-write endpoint
class PostList(generics.ListCreateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer

# RetrieveUpdateDestoryAPIView -> ALlows read, update, delete
class PostDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer


ブラウザをリフレッシュしてみるとログイン前の場合、更新がかけられなくなっていることがわかる。

スクリーンショット 2018-10-01 6.25.18.png


■ カスタムパーミッション

パーミッションをカスタマイズできるらしい。


terminal

(blogapi-H-RPCYMU) $ touch posts/permissions.py


カスタムパーミッションを作るには、Django REST Framework のBasePermission クラスの has_object_permission をオーバーライドする。


posts/permissions.py

from rest_framework import permissions

class IsAuthorOrReadOnly(permissions.BasePermission):

def has_object_permission(self, request, view, obj):
# Read-only permissions are allowed for any request
if request.method in permissions.SAFE_METHODS:
return True

# Write permissions are only allowed to the author of a post
return obj.author == request.user


views.py も修正する。


posts/views.py

from rest_framework import generics

from .models import Post
from .permissions import IsAuthorOrReadOnly # 追加
from .serializers import PostSerializer

# ListCreateAPIView -> read-write endpoint
class PostList(generics.ListCreateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer

# RetrieveUpdateDestoryAPIView -> ALlows read, update, delete
class PostDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = (IsAuthorOrReadOnly,) # 追加
queryset = Post.objects.all()
serializer_class = PostSerializer


ローカルサーバを起動して、localhost:8000/api/v1/1/ にアクセスしてみる。

・管理者

スクリーンショット 2018-10-02 6.23.10.png

・一般ユーザ

スクリーンショット 2018-10-02 6.22.56.png


■認証

Django REST Framework の認証について見てみよう。

DEFAULT_AUTHENTICATION_CLASSESで認証をかけられるようだ。


blog_project/settings.py

REST_FRAMEWORK = {

'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_AUTHENTICATION_CLASSES': [ # 追加
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
],
}

BasicAuthentication は、セッション ID を HTTP ヘッダに入れて、API に渡す役割を持ち、

SessionAuthentication は、ブラウザにログイン、ログアウトの機能を提供するらしい。


■認証トークン

先ほど実装した認証にトークンを利用できるようにする。

DEFAULT_AUTHENTICATION_CLASSES を以下のように修正する。


log_project/settings.py

REST_FRAMEWORK = {

'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication', # 変更
],
}

サーバー上でトークンを作成するために、authtoken app を Django に追加する。


log_project/settings.py

INSTALLED_APPS = [

# Local
'posts.apps.PostsConfig',

# 3rd-party apps
'rest_framework',
'rest_framework.authtoken', # 追加

'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]


INSTALLED_APPS に変更を加えたら DATABASE と同期させるために、マイグレートを実施する。

もしローカルサーバーを起動している場合は、Ctrl + c で止めて、以下のコマンドを実行しよう。


terminal

(blogapi-H-RPCYMU) $ python manage.py migrate

(blogapi-H-RPCYMU) $ python manage.py runserver

http://localhost:8000/admin/ にアクセスすると「Tokens」の欄ができている。

スクリーンショット 2018-10-03 6.27.48.png

Tokens をクリックしても現在は何も設定されていないが、あとで使おう。


■ Django-Rest-Auth

django-rest-auth を使って、ログイン・ログアウトやパスワードのリセット機能を実装する。

ローカルサーバーを一旦止めて、terminal 上で、以下のコマンドを押下する。


terminal

(blogapi-H-RPCYMU) $ pipenv install django-rest-auth==0.9.3


次に、INSTALLED_APPS に django-rest-auth を追加する。


blog_project/settings.py

INSTALLED_APPS = [

# Local
'posts.apps.PostsConfig',

# 3rd-party apps
'rest_framework',
'rest_framework.authtoken',
'rest_auth', # 追加

'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]


これで、Django は、django-rest-auth を認識するので、ルーティングの設定をしよう。


blog_project/urls.py

from django.contrib import admin

from django.urls import include, path

urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('posts.urls')),
path('api-auth/', include('rest_framework.urls')),
path('api/v1/rest-auth/', include('rest_auth.urls')), # 追加
]


ローカルサーバーを動かして、localhost:8000/api/v1/rest-auth/login/ にアクセスしてみよう。

スクリーンショット 2018-10-04 5.53.33.png

うまくいっている。

localhost:8000/api/v1/rest-auth/logout/ にもアクセスする。

スクリーンショット 2018-10-04 5.54.08.png

これも大丈夫だ。

localhost:8000/api/v1/rest-auth/password/reset/ はどうだろうか。

スクリーンショット 2018-10-04 5.55.45.png

reset も大丈夫だ。

http://localhost:8000/api3/v1/rest-auth/password/reset/confirm/ っていうのもある。

スクリーンショット 2018-10-04 5.56.59.png

たった数行のコードで、ログイン・ログアウト、リセット、リセット確認を実装できた。

もう、ゴリゴリコーディングする時代じゃないのかもしれない。


■ サインアップの実装

サインインとサインアップは名前は似ているが、役割が違う。

サインインは登録済みのユーザーの認証をに使われ、サインアップはユーザー登録と認証を同時にやる。

django-allauth を使って実装しよう。

ローカルサーバを停止して、terminal 上で、以下のコマンドをうつ。

(blogapi-H-RPCYMU) $ pipenv install django-allauth==0.37.1

インストールが完了したらいつも通り、INSTALLED_APPS に追加する。


blog_project/settings.py

INSTALLED_APPS = [

# Local
'posts.apps.PostsConfig',

# 3rd-party apps
'rest_framework',
'rest_framework.authtoken',
'allauth', # 追加
'allauth.account', # 追加
'allauth.socialaccount', # 追加
'rest_auth',
'rest_auth.registration', # 追加

'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites', # 追加
]

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
SITE_ID = 1


EMAIL_BACKENDは、ユーザーの登録した時に Email でも認証確認する時に使う機能だ。

SITE_ID は、sites フレームワークの一つで、いくつかの Django プロジェクトからたくさんの Web サイトをホストするための機能らしい。

今回は、どちらも使わないと思うが、一応推奨設定らしいので入れておく。

マイグレーションも行う。


terminal

(blogapi-H-RPCYMU) $ python manage.py migrate


最後にルーティングの設定を行う。


blog_project/urls.py

from django.contrib import admin

from django.urls import include, path

urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('posts.urls')),
path('api-auth/', include('rest_framework.urls')),
path('api/v1/rest-auth/', include('rest_auth.urls')),
path('api/v1/rest-auth/registration/',
include('rest_auth.registration.urls')),
]


ローカルサーバを起動して、localhost:8000/api/v1/rest-auth/registration/ にアクセスする。

スクリーンショット 2018-10-05 6.02.32.png

登録画面が表示できたら、設定が成功している。

ちょっと前に認証トークンの設定を行ったと思う。

この画面でユーザーを新規登録すると認証トークンも発行されるようだ。

super_testuser を登録してみる。

スクリーンショット 2018-10-06 6.10.46.png

パスワードが短すぎて、怒られた。こういうチェック機能もついてるんだな。

スクリーンショット 2018-10-06 6.11.09.png

パスワードを長くしてみる。

スクリーンショット 2018-10-06 6.11.33.png

登録が成功するとトークンの Key が発行された。

スクリーンショット 2018-10-06 6.11.47.png

terminal を確認すると以下のように表示されている。


terminal

Content-Type: text/plain; charset="utf-8"

MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: [example.com] Please Confirm Your E-mail Address
From: webmaster@localhost
To: sample@example.com
Date: Fri, 05 Oct 2018 21:11:38 -0000
Message-ID: <153877389860.996.13583794322804618519@onoakirBookpuro>

Hello from example.com!

You're receiving this e-mail because user super_testuser has given yours as an e-mail address to connect their account.

To confirm this is correct, go to http://localhost:8000/api/v1/rest-auth/registration/account-confirm-email/MQ:1g8XNq:lmi6ArNuZvT6rkybjEjvAF03BIc/

Thank you from example.com!
example.com


これは、django-allauth で作っているらしく、SMTP サーバーに設定を行うとメール通知ができるようになるらしい。

http://localhost:8000/admin/authtoken/token/ にアクセスしてみるとさっき登録した super_testuser が登録されていることがわかる。

スクリーンショット 2018-10-06 6.22.58.png


■ ユーザーリスト

Viewsetsrouters は、API の開発を加速させるツールだ。

これらを使って、既存のユーザの一覧をブラウザ上に表示させるAPIを作成する。(多分管理者には、必要な機能なんじゃないかな)

まずは、シリアライズクラスを作成する。


posts/serializers.py

from django.contrib.auth import get_user_model # 追加

from rest_framework import serializers
from .models import Post

class PostSerializer(serializers.ModelSerializer):

class Meta:
fields = ('id', 'author', 'title', 'body', 'created_at',)
model = Post

# 追加
class UserSerializer(serializers.ModelSerializer):

class Meta:
model = get_user_model()
fields = ('id', 'username',)


次は、view の設定を行う。


posts/views.py

from django.contrib.auth import get_user_model # 追加

from rest_framework import generics

from .models import Post
from .permissions import IsAuthorOrReadOnly
from .serializers import PostSerializer, UserSerializer # 追加

# ListCreateAPIView -> read-write endpoint
class PostList(generics.ListCreateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer

# RetrieveUpdateDestoryAPIView -> ALlows read, update, delete
class PostDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = (IsAuthorOrReadOnly,)
queryset = Post.objects.all()
serializer_class = PostSerializer

# 追加
class UserList(generics.ListCreateAPIView):
queryset = get_user_model().objects.all()
serializer_class = UserSerializer

# 追加
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = get_user_model().objects.all()
serializer_class = UserSerializer


最後に urls の設定を行う。


posts/urls.py

from django.urls import path

from .views import PostList, PostDetail, UserList, UserDetail

urlpatterns = [
path('<int:pk>/', PostDetail.as_view()),
path('', PostList.as_view()),
path('users/', UserList.as_view()),
path('users/<int:pk>/', UserDetail.as_view()),
]


設定が完了したらローカルサーバーを起動して、localhost:8000/api/v1/users/ にアクセスしよう。

スクリーンショット 2018-10-07 6.16.37.png

うまくいった。筆者の環境だと、5 ユーザーいる。

localhost:8000/api/v1/users/1 にアクセスすると詳細画面が見れる。

スクリーンショット 2018-10-07 6.18.25.png

Viewsets の機能は、これだけじゃないらしい。


■ View の統合

現時点での View は、PostList、PostDetail、UserList、UserDetail の 4 つある。

これを viewsets を使って統合する。


posts/views.py

from django.contrib.auth import get_user_model

from rest_framework import viewsets

from .models import Post
from .permissions import IsAuthorOrReadOnly
from .serializers import PostSerializer, UserSerializer

class PostViewSet(viewsets.ModelViewSet):
permission_classes = (IsAuthorOrReadOnly,)
queryset = Post.objects.all()
serializer_class = PostSerializer

class UserViewset(viewsets.ModelViewSet):
queryset = get_user_model().objects.all()
serializer_class = UserSerializer


次は、ルーティングを変更する。

SimpleRouterを使えば、url を統合できるらしい。


posts/urls.py

from django.urls import path

from rest_framework.routers import SimpleRouter

from .views import UserViewset, PostViewSet

router = SimpleRouter()
router.register('users', UserViewset, base_name='users')
router.register('', PostViewSet, base_name='posts')

urlpatterns = router.urls


ローカルサーバーを立ち上げて、localhost:8000/api/v1/users/ にログインする。

スクリーンショット 2018-10-07 17.29.58.png

うまくいったようだ。

localhost:8000/api/v1/users/1 にアクセスして、詳細画面を表示してみる。

スクリーンショット 2018-10-07 17.31.29.png

こちらもうまくいっているみたいだが、先ほどとは表示のされ方が若干異なっている。

Post の方も見てみる。

localhost:8000/api/v1 にアクセスする。

スクリーンショット 2018-10-07 17.33.40.png

localhost:8000/api/v1/1 にアクセスする。

スクリーンショット 2018-10-07 17.33.52.png

うまくいっているようだ。

ちなみに、Post の方には、read only のパラメータをつけている。

permission_classes = (IsAuthorOrReadOnly,)

super_testuser は、一般ユーザー(superがついているけど)なので、詳細画面上で書き換えができないが、

管理者ユーザーの場合は、編集できるようになっている。

スクリーンショット 2018-10-07 17.35.03.png


■ API の見える化

Django REST Framework では、Core API を使って、API のスキーマーを自動的に作り出すことができるらしい。

早速インストールしよう。

ローカルサーバーを起動している場合は、Ctrl + c で止めてから、terminal 上で、以下のコマンドを実行する。

(blogapi-H-RPCYMU) $ pipenv install coreapi==2.3.3

インストールしたら、Django に Core API を認識させる。


blog_project/urls.py

from django.contrib import admin

from django.urls import include, path
from rest_framework.schemas import get_schema_view # 追加

schema_view = get_schema_view(title='Blog API') # 追加

urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('posts.urls')),
path('api-auth/', include('rest_framework.urls')),
path('api/v1/rest-auth/', include('rest_auth.urls')),
path('api/v1/rest-auth/registration/',
include('rest_auth.registration.urls')),
path('schema/', schema_view), # 追加
]

ここまで設定が完了したら、ローカルサーバーを立ち上げて、localhost:8000/schema/ にアクセスしよう。

スクリーンショット 2018-10-08 4.56.03.png

うまくいったようだ。

ただ、このスキーマーは、ちょっと読みにくいので、読みやすくする設定を行う。


blog_project/urls.py

from django.contrib import admin

from django.urls import include, path
from rest_framework.documentation import include_docs_urls # 追加
from rest_framework.schemas import get_schema_view

schema_view = get_schema_view(title='Blog API')

urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('posts.urls')),
path('api-auth/', include('rest_framework.urls')),
path('api/v1/rest-auth/', include('rest_auth.urls')),
path('api/v1/rest-auth/registration/',
include('rest_auth.registration.urls')),
path('docs/', include_docs_urls(title='Blog API')), # 追加
path('schema/', schema_view),
]


localhost:8000/docs/ にアクセスしてみる。

スクリーンショット 2018-10-08 5.01.54.png

おお、なんかかっこよくなった。

blog_project/urls.py をちょっと整理する。


blog_project/urls.py

from django.contrib import admin

from django.urls import include, path
from rest_framework.documentation import include_docs_urls
from rest_framework.schemas import get_schema_view

API_TITLE = 'Blog API'
API_DESCRIPTION = 'A Web API for creating and editing blog posts.'
schema_view = get_schema_view(title=API_TITLE)

urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('posts.urls')),
path('api-auth/', include('rest_framework.urls')),
path('api/v1/rest-auth/', include('rest_auth.urls')),
path('api/v1/rest-auth/registration/',
include('rest_auth.registration.urls')),
path('docs/', include_docs_urls(title=API_TITLE,
description=API_DESCRIPTION)),
path('schema/', schema_view),
]


もう一度、localhost:8000/docs/ にアクセスする。

スクリーンショット 2018-10-08 5.07.37.png


■ Django REST Swagger

他にも Django REST Swagger という便利なパッケージがある。

ローカルサーバーを一旦止めて、以下をインストールする。


terminal

(blogapi-H-RPCYMU) $ pipenv install django-rest-swagger==2.2.0


そして、いつもの通り、Django に認識させる。


blog_project/settings.py

INSTALLED_APPS = [

# Local
'posts.apps.PostsConfig',

# 3rd-party apps
'rest_framework',
'rest_framework.authtoken',
'rest_framework_swagger', # 追加
'allauth',
'allauth.account',
'allauth.socialaccount',
'rest_auth',
'rest_auth.registration',

'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
]


blog_project/urls.py を書き換える。


blog_project/urls.py

from django.contrib import admin

from django.urls import include, path
from rest_framework.documentation import include_docs_urls
from rest_framework.schemas import get_schema_view
from rest_framework_swagger.views import get_swagger_view # 追加

API_TITLE = 'Blog API'
API_DESCRIPTION = 'A Web API for creating and editing blog posts.'
# schema_view = get_schema_view(title=API_TITLE) # 追加
schema_view = get_swagger_view(title=API_TITLE) # 追加

urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('posts.urls')),
path('api-auth/', include('rest_framework.urls')),
path('api/v1/rest-auth/', include('rest_auth.urls')),
path('api/v1/rest-auth/registration/',
include('rest_auth.registration.urls')),
path('docs/', include_docs_urls(title=API_TITLE,
description=API_DESCRIPTION)),
# path('schema/', schema_view), # 追加
path('swagger-docs/', schema_view), # 追加
]

ローカルサーバーを起動して、localhost:8000/swagger-docs/ にアクセスする。

スクリーンショット 2018-10-08 5.20.51.png

おお、すごい。

こういうの現場でガンガン入れたいな、と思いました。


■ 参考

Djang REST Framework Quickstart


■ まとめ

Django Rest Framework のチュートリアルを見てみると結構、色々な機能がある。

まだまだ勉強しないといけないことがあるようだ。