💚

Django REST FrameworkでAPIを作成してみた

2023/10/07に公開

背景

以前からDjangoにおけるWebアプリケーション作成において、ReactやFlutterなどのフロントエンドのフレームワークとの結合を考えております。
今回は、それに先立ちフロントエンドとバックエンドとのやりとりをDjango REST Frameworkを利用したRESTful APIで行なうために学習した記録です。

先人たちの知恵をお借りするなどして解決できたことを、この場をお借りして感謝するとともに、大変恐縮ですが自分のメモとして、こちらへまとめておきます。

はじめに

チグサさんのブログ:「チグサウェブ」の記事を参考に、Django REST Frameworkを利用して、RESTful APIを作成してみました。
大変分かりやすくまとまっており、これから学習する方にもオススメです。

今回、チグサさんの記事と異なり、dockerでの環境構築やDjangoで利用するデータベースの変更は省いています。

https://chigusa-web.com/

そもそもAPIとは?

Application Programming Interfaceの略。
今回作成するのはHTTPやHTTPS通信でデータのやり取りを行うことができる、Web APIです。

Django REST Frameworkとは?

Django REST Framework (DRF)とはRESTful API開発に特化したDjangoのフレームワークです。
DRFを使うことでよりRESTfulなWebアプリケーションを作成することができます。

RESTful APIとはRESTという原則を守っているHTTP呼び出しインターフェースのことです。
Django REST Frameworkを使用することにより、Djangoフレームワークで簡単にAPIの実装ができる優れもの。
バックエンドのAPIサーバーを実装する際に大変便利です。

https://www.django-rest-framework.org/

1.python仮想環境の構築

Python環境に、venvにより仮想環境を構築します。(すでにPython実行環境は構築済みの前提です。)
以下のコマンドを実行します。

python -m venv venv
ディレクトリ構成
venv
├ Include
├ Lib
└ Scripts
pyvenv.cfg

以下のコマンドで仮想環境を有効にします。

cd venv\Scripts
activate.bat

以下のコマンドでpipをupgradeします。

(venv) python -m install --upgrade pip

2.Djangoのインストール

以下のコマンドでdjangoをインストールします。

(venv) pip install django

https://www.djangoproject.com/

3.Djangoプロジェクトの作成

以下のコマンドで、Djangoプロジェクトを作成します。
最後に「.」(ドット)を付けることで、同じ階層にプロジェクトファイルを作成しています。

(venv) django-admin startproject djangoApiApp .
ディレクトリ構成
venv
├ Include
├ djangoApiApp  # 追加
  ├ __pycache__
  ├ __init__.py
  ├ asgi.py
  ├ settings.py
  └ wsgi.py
├ Lib
└ Scripts
db.sqlite3
manage.py
pyvenv.cfg

4.Djangoのデータベースの設定

デフォルトでsqlite3が指定されていますので、今回はこのまま使います。

djangoApiApp/settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

言語とタイムゾーンの項目を修正します。

djangoApiApp/settings.py
LANGUAGE_CODE = 'ja'       # 修正

TIME_ZONE = 'Asia/Tokyo'   # 修正

今回は、これらを管理するツールとして便利なdjango-environを使います。

django-environのインストール

django-environは外部モジュールなのでインストールする必要があります。
Djangoアプリケーションが動作しているPython環境で、次のコマンドを実行します。

(venv) pip install django-environ

インストールはこれだけです。

https://django-environ.readthedocs.io/en/latest/

.envファイルの作成と記述

manage.pyと同じ階層(今回の構成ではdjandoプロジェクト直下)に「.env」という名前でファイルを作成します。

ディレクトリ構成
venv
├ Include
├ djangoApiApp
  ├ __pycache__
  ├ __init__.py
  ├ asgi.py
  ├ settings.py
  └ wsgi.py
├ Lib
└ Scripts
.env              # 追加
db.sqlite3
manage.py
pyvenv.cfg

このファイルに環境変数などの機密情報を分離します。

.env
SECRET_KEY=django-insecure-*************************************
DEBUG=True

DATABASE_ENGINE=django.db.backends.sqlite3  # 使用するDBのエンジン(sqlite3ならdjango.db.backends.sqlite3)
DATABASE_DB=db.sqlite3                      # データベース名(sqlite3ならdb.sqlite3)
DATABASE_USER=django_user                   # defaultのままで可
DATABASE_PASSWORD=password                  # defaultのままで可
DATABASE_HOST=localhost                     # defaultのままで可
DATABASE_PORT=5432                          # defaultのままで可

=の前後に半角スペースが入ったり、文字列をシングルクォーテーションで囲っていたりするとエラーになるので注意しましょう。

settings.pyで環境変数を呼び出す

.envファイルに環境変数をsettings.pyで呼び出します。

djangoApiApp/settings.py
import os                       # 追加
import environ                  # 追加
 
env = environ.Env()             # 追加
env.read_env('.env')            # 追加
 
SECRET_KEY = env('SECRET_KEY')  # 修正
DEBUG = env('DEBUG')            # 修正
 
DATABASES = {
    'default': {
        'ENGINE': env.get_value('DATABASE_ENGINE', default='django.db.backends.sqlite3'),      # 修正
        'NAME': env.get_value('DATABASE_DB', default=os.path.join(BASE_DIR, 'db.sqlite3')),    # 修正
        'USER': env.get_value('DATABASE_USER', default='django_user'),                         # 追加
        'PASSWORD': env.get_value('DATABASE_PASSWORD', default='password'),                    # 追加
        'HOST': env.get_value('DATABASE_HOST', default='localhost'),                           # 追加
        'PORT': env.get_value('DATABASE_PORT', default='5432'),                                # 追加
    }
}

これだけ!

5.Django REST Frameworkのインストール

Djangoアプリケーションが動作しているPython環境に、Django REST Frameworkをインストールします。

(venv) pip install djangorestframework

6.アプリ追加と設定

以下のコマンドで、Djangoプロジェクトにアプリケーションを追加します。
商品マスターを想定したアプリケーションとして、APIを実装します。

(venv) python manage.py startapp products
ディレクトリ構成
venv
├ Include
├ djangoApiApp
  ├ __pycache__
  ├ __init__.py
  ├ asgi.py
  ├ settings.py
  └ wsgi.py
├ Lib
├ products       # 追加
  ├ __pycache__
  ├ migtarions
  ├ __init__.py
  ├ admin.py
  ├ apps.py
  ├ models.py
  ├ tests.py
  └ views.py
└ Scripts
.env
db.sqlite3
manage.py
pyvenv.cfg

djangoプロジェクトのsettings.pyに、アプリケーションを追加します。

djangoApiApp/settings.py
INSTALLED_APPS = [
...
    'rest_framework',  # 追加
    'products',        # 追加
]

7.Modelとテーブルの作成

テーブル定義に合わせたモデルを作成します。
今回は商品を想定したモデルとしました。

products/models.py
# 以下を追加
class Product(models.Model):

    name = models.CharField(max_length=200)
    price = models.IntegerField()

以下のコマンドでマイグレーションファイルを作成します。

(venv) python manage.py makemigrations products

以下のファイルが自動で作成されます。

products/migrations/0001_initial.py
# Generated by Django 4.0.3 on 2022-04-06 13:44

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Product',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=200)),
                ('price', models.IntegerField()),
            ],
        ),
    ]

以下のコマンドでマイグレーションを実行し、テーブルを作成します。

(venv) python manage.py migrate

管理画面での確認

Djangoの管理画面から確認してみましょう。
まずは、管理画面にログインするためのユーザを作成します。

以下のコマンドを実行します。

(venv) python manage.py createsuperuser

以下のコマンドで開発サーバーを起動します。

(venv) python manage.py runserver

以下のURLにアクセスします。

http://localhost:8000/admin/

管理画面が表示されますので、先ほど作成したユーザでログインします。
スクリーンショット 2023-10-07 210240.png

管理画面にアクセスすることができました。
スクリーンショット 2023-10-07 181116.png

今回テーブルを作成した商品マスタを編集できるようするため、以下のファイルを修正します。

products/admin.py
from django.contrib import admin

# Register your models here.

from .models import Product   # 追加

admin.site.register(Product)  # 追加

画面を更新すると、商品テーブルのマスタメンテが追加されました。
スクリーンショット 2023-10-07 181303.png

ここから新規登録などができます。
スクリーンショット 2023-10-07 181410.png

一覧を表示すると、「xx object (1)」のように表示されます。
スクリーンショット 2023-10-07 181428.png

名前が表示されるように、モデルを修正します。

products/models.py
from django.db import models

# Create your models here.

class Product(models.Model):

    name = models.CharField(max_length=200)
    price = models.IntegerField()

    # 以下を追加
    def __str__(self):
        return self.name

画面を更新すると、一覧に名前が表示されるようになりました!
スクリーンショット 2023-10-07 181538.png

8.Serializerクラスの作成

APIでデータのやり取りを行うためのSerializer(シリアライザー)を設定するため、以下のファイルを作成します。

products/serializers.py
# 以下を追加
from rest_framework import serializers
from .models import Product


class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = ['name', 'price']
ディレクトリ構成
venv
├ Include
├ djangoApiApp
  ├ __pycache__
  ├ __init__.py
  ├ asgi.py
  ├ settings.py
  └ wsgi.py
├ Lib
├ products
  ├ __pycache__
  ├ migtarions
  ├ __init__.py
  ├ admin.py
  ├ apps.py
  ├ models.py
  ├ serializers.py  # 追加
  ├ tests.py
  └ views.py
└ Scripts
.env
db.sqlite3
manage.py
pyvenv.cfg

Django REST Frameworkの最大の特徴はこのSerializerと言っても過言ではありません。
Serializerについては、「Django REST Framework の特徴(Serializer)」のセクションでの説明が参考になります。

https://qiita.com/pythonista/items/1babe212609aa159af77#django-rest-framewrk-の特徴serializer

9.Viewの作成

APIの処理を、ViewSetを使用して実装します。
これにより例えば、一覧や詳細データの取得、新規登録、更新、削除などが処理できるようになります。

ここではModelViewSetを使用して、以下のように実装します。

products/views.py
# 以下を上書き
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer


class ProductViewSet(viewsets.ModelViewSet):

    queryset = Product.objects.all()
    serializer_class = ProductSerializer

10.URLの追加

APIを呼び出すためのURLをアプリケーションのurls.pyに追加します。
ViewSetをルーターに登録します。

products/urls.py
# 以下を追加
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ProductViewSet

router = DefaultRouter()
router.register('products', ProductViewSet)

urlpatterns = [
    path('', include(router.urls)),
]
ディレクトリ構成
venv
├ Include
├ djangoApiApp
  ├ __pycache__
  ├ __init__.py
  ├ asgi.py
  ├ settings.py
  └ wsgi.py
├ Lib
├ products
  ├ __pycache__
  ├ migtarions
  ├ __init__.py
  ├ admin.py
  ├ apps.py
  ├ models.py
  ├ serializers.py
  ├ tests.py
  ├ urls.py  # 追加
  └ views.py
└ Scripts
.env
db.sqlite3
manage.py
pyvenv.cfg

djangoプロジェクトのurls.pyに追加します。
パスは任意で指定できます。今回は「products/」としました。

djangoApiApp/urls.py
from django.contrib import admin
from django.urls import path, include  # includeを追加

urlpatterns = [
    path('admin/', admin.site.urls),

    # API
    path('products/', include('products.urls')),  # 追加
]

11.APIの確認

API画面

起動していない場合は、以下のコマンドで開発サーバーを起動しましょう。

(venv) python manage.py runserver

以下のURLにアクセスします。

http://localhost:8000/products/

APIを操作するための画面が表示されます。
スクリーンショット 2023-10-07 183500.png

curlコマンドなどでAPIへアクセスすると、実際に使用する際はJSON形式のデータを取得できることが分かります。

(venv) curl http://localhost:8000/products/

# {"products":"http://localhost:8000/products/products/"}

データ編集

一覧を表示するためのURLにアクセスします。

http://localhost:8000/products/products/

一覧のデータと、新規登録のためのフォームが表示されます。
このフォームからデータが追加できますので、試してみてください。
スクリーンショット 2023-10-07 183609.png

詳細を表示するためのURLにアクセスします。(末尾にIDを指定)

http://localhost:8000/products/products/1/

詳細画面が開き、データの編集や削除などができます。
スクリーンショット 2023-10-07 183658.png

最低限のコードで、一覧、詳細、新規登録、編集、削除を処理するAPIが実装できました。

12.ViewSetについて

APIView

Modelに紐づかないようなViewも作成できます。
これはAPIViewクラスを使用して、ダミーデータを返却するようなAPIの実装例です。

products/views.py
from rest_framework.views import APIView      # 追加
from rest_framework.response import Response  # 追加

...
# 以下を追加
class ProductDummyApiView(APIView):

    def get(self, request, format=None):
        return Response({"name": "DUMMY!"})   # ダミーデータを返却

URLを追加します。

products/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ProductViewSet, ProductDummyApiView  # ProductDummyApiViewを追加

router = DefaultRouter()
router.register('products', ProductViewSet) 

urlpatterns = [
    path('', include(router.urls)),

    path("dummy/", ProductDummyApiView.as_view()),  # 追加
]

以下のURLにアクセスします。

http://localhost:8000/products/dummy/

ダミーデータを取得できました!
スクリーンショット 2023-10-07 183851.png

api_view

こちらは関数ベースのapi_viewにより、Modelのデータ一覧を表示する処理の実装例です。

products/views.py
from rest_framework.decorators import api_view  # 追加

...
# 以下を追加
@api_view(['GET'])
def product_list(request):

    if request.method == 'GET':
        products = Product.objects.all()
        serializer = ProductSerializer(products, many=True)
        return Response(serializer.data)

ModelViewSetのように、ModelとSerializerを使用して、一覧を返却する処理にします。

URLを追加します。

products/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ProductViewSet, ProductDummyApiView, product_list  # product_listを追加

router = DefaultRouter()
router.register('products', ProductViewSet)

urlpatterns = [
    path('', include(router.urls)),
    path("dummy/", ProductDummyApiView.as_view()),

    path('list/', product_list),  # 追加
]

以下のURLにアクセスします。

http://localhost:8000/products/list/

商品の一覧を取得できました!
スクリーンショット 2023-10-07 184221.png


今回のソースコードはGitHubにコミット済みです。

https://github.com/whitecat-22/drf_crud


参考

https://chigusa-web.com/blog/django-rest-framework/


(編集後記)

今回はDjango REST Framework (DRF)を利用して、RESTfulなAPIを作成してみましたが、実装は簡単ですし、画面を通じて確認を行なえるためユーザーフレンドリーです。
バックエンドのAPIを作る際には、選択肢のひとつとしてDRFは大いに利用できるものと分かりました。

ここまでの手順を基に、今後もDjangoによるWebアプリケーション作成をすすめてみます。
皆様の参考になれば幸いです。

今後、フロントエンドにReactまたはFlutterを結合したWebアプリケーションの作成に移りたいのですが、どちらを選ぶかで躊躇している状態でして、両者のメリデメをよく検討した上で決定したいと思います。

Discussion