Django REST Framework で API 作成

# はじめに

フロントエンド [React.js] & バックエンド [Django REST Framework] という組み合わせでウェブアプリ開発をしてみる。この記事では、DRF でウェブ API を作成しフロントエンド側からデータを取得できるようにする。動作環境は以下。

- OS: Windows 10 Pro (WSL2 Ubuntu-20.04)
- Python: 3.8.5
- Django: 3.2
- djangorestframework: 3.12.4

# インストールおよびセットアップ

DRF をインストールし、使用できる状況にするためのセットアップについて説明する。Django 自体のインストールやプロジェクトの作成などといった基本的な説明は割愛する。
まず以下コマンドで DRF をインストールする。

```
$ pip install djangorestframework
```

続いて、API を作成したいプロジェクトの settings.py にて 'rest_framework' を追記する。

```python:config/settings.py
# Application definition

INSTALLED_APPS = [
    ...
    'rest_framework',
]
```

これで DRF を読み込んで、使用することができる。

# ウェブ API 作成の流れ

DRF を用いたウェブ API を作成するには、__Model, Serializer, ViewSet, URL パターン__ の4項目を定義する必要がある。api というアプリを作成し、それぞれ準備していく。

# Model

Model は、データベースのレコードをモデルクラスのオブジェクトとして扱うことができる。一からモデルクラスを定義することもできるが、ここでは既存のデータベースからモデルを自動で定義する。既存のデータベースを利用する方法は、[Djangoで既存のPostgreSQLを利用](https://qiita.com/honda28/items/d5bf743c3c244791f559)を参照。
たとえば、ID と時刻、緯度経度をもつようなデータベースを使うと、以下のようなモデルが定義されるので、これを用いていく。

```python:api/models.py
from django.db import models

class Info(models.Model):
    id = models.CharField(primary_key=True, max_length=12)
    utcdate = models.DateTimeField()
    latitude = models.DecimalField(max_digits=8, decimal_places=6)
    longitude = models.DecimalField(max_digits=9, decimal_places=6)

    class Meta:
        managed = False
        db_table = 'info'
        unique_together = (('id', 'utcdate'),)
```

# Serializer

Serializer は、クエリセットやモデルインスタンスなどの複雑なデータを変換することができる。上記で定義した Model を読み込んで Serializer を定義すると、以下のようになる。

```python:api/serializers.py
from rest_framework import serializers
from .models import Info

class InfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Info
        fields = '__all__'
```

# ViewSet

Viewset は、これまでに定義した Model のオブジェクトや Serializer を指定して、どのように扱うかを決める。Viewset は以下のようになる。

```python:api/views.py
from .models import Info
from .serializers import InfoSerializer
from rest_framework import viewsets

class InfoViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Info.objects.all()
    serializer_class = InfoSerializer
```

ReadOnly の ViewSet を継承して、クエリセットに Info オブジェクトの全データ、シリアライザークラスに InfoSerializer を指定している。

# URL パターン

URL パターンは、リクエストがどの ViewSet に対応するかを振り分ける。DRF には router という機能があり、ここに URL パターンを登録する。router を使わない通常の設定でも可能。

```python:api/ursl.py
from django.urls import path, re_path, include
from rest_framework.routers import DefaultRouter
from . import views

app_name = 'api'
router = DefaultRouter()
router.register(r'info', views.InfoViewSet)

# The API URLs are now determined automatically by the router.
urlpatterns = [
    path('', include(router.urls)),
]
```

プロジェクトの urls.py にて、上記で設定した URL パターンを読み込む。

```python:config/ursl.py
from django.contrib import admin
from django.urls import include, path

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


# API 動作確認

ここまでで API が作成できているはずなので、開発用サーバーにて動作確認をする。`python manage.py runserver` で開発用サーバーを立ち上げ、[http://localhost:8000/api/](http://localhost:8000/api/) にアクセスすると API コンソールが立ち上がることが確認できる。さらに [http://localhost:8000/api/info](http://localhost:8000/api/info/) へアクセスすると、定義したデータを取得できるエンドポイントができていることが確認できる。

# おわりに

DRF でウェブ API を作成した。React.js で作成したフロントエンドから今回作成した API のデータを取得したり、リクエストに応じてデータをフィルタリングするということを追加で実践していく。