logo
Search
Programming

React × DRFで画像アップロード機能作成 (バックエンド実装編)

#React #Django REST Framework
Oct 26th 2021 Oct 27th 2021
React × DRFで画像アップロード機能作成 (バックエンド実装編)

前回までで、環境構築・フロントエンド側の実装が完了したので、続いてバックエンド側の実装に移りたいと思います。

前回までの記事

実行環境

  • Mac OS X 11.2.1
  • Docker 20.10.5
  • docker-compose version 1.28.5
  • node v15.10.0
  • npm 7.9.0
  • react 17.2.0

コンテナに入る

今回は、server用のコンテナに入って作業をしていきます。下記コマンドを実行して、serverコンテナに入ります。

$ docker exec -it server bash

Django Projectの作成

コンテナに入ったら、まず初めにDjangoのProjectを作成していきます。下記コマンドで、Django Projectを作成します。

$ django-admin startproject server

上記コマンドを実行すると下記のようなファイルたちが生成されます。

server/
    manage.py
    server/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py

Django Appの作成

Projectの作成が完了したら、続いてはAppの作成をしていきます。
下記コマンドで、Django Appを作成します。

$ python manage.py startapp api

上記コマンドを実行することで、apiというディレクトリを作成されます。

server/
    manage.py
    server/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py
		polls/
		    __init__.py
		    admin.py
		    apps.py
		    migrations/
		        __init__.py
		    models.py
		    tests.py
		    views.py

Djangoの開発サーバで確認してみる

正常にDjangoのファイルたちが作成されているか確認するために、Djangoが用意している開発サーバを立てて、確認をしてみます。下記コマンドを実行して、サーバを立てます。

$ python manage.py runserver 0.0.0.0:8000

サーバが立ち上がったら、ブラウザからhttp://localhost:8000/へアクセスします。

下記画面が表示されたら、確認は完了です。
django serverup


ここまでの手順は、Djangoの公式サイトのチュートリアルに沿った形で実行しています。各コマンドの詳細が気になる方は、公式サイトを確認してみてください。

Django公式tutorial

実装

設定ファイルの修正

早速実装に移っていこうと思いますが、その前に実装を始める前の準備段階として設定ファイル等を修正していきます。

/server/server/settings.pyをエディターで開きます。

ALLOWED_HOSTS = ['*'] # 修正

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework', # 追記
    'api.apps.ApiConfig', # 追記
    'corsheaders', # 追記
]

MIDDLEWARE = [
    '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',
    'corsheaders.middleware.CorsMiddleware' # 追記
]

# 追記
CORS_ORIGIN_WHITELIST = (
    'http://localhost:3000',
)

LANGUAGE_CODE = 'ja' # 修正

TIME_ZONE = 'Asia/Tokyo' # 修正

# 追記
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

上記のようにsettings.pyを修正します。
※関係のない部分は省略しています。

mediaディレクトリの用意

上記のsettings.pyでMEDIA_URLMEDIA_ROOTを定義しました。

こちらは、画像の保存先を指定しており、画像が保存されると指定したmediaディレクトリ内に保存しようとします。そのため、事前に空のmediaディレクトリを用意しておいてください。

ルーティングの設定

続いて、ルーティングの設定を行っていきます。まず、/server/server/urls.pyをエディターで開きます。

from django.contrib import admin
from django.urls import path, include
from django.contrib.staticfiles.urls import static
from . import settings

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

urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

次に、前回作成したapiアプリ内にurls.pyを作成して下記コードを記述します。

from django.db import router
from django.urls import path, include
from . import views
from rest_framework.routers import DefaultRouter

router = DefaultRouter()

urlpatterns = [
    path('image/', views.ImageFileView.as_view(), name='images'),
    path('', include(router.urls)),
]

これでルーティングの設定が完了しました。

流れとしては、example.com/api/imageというURLがあったとして、はじめに、server/urls.pyをみて、api/ というパスが存在するので、includeしてあるapi/urls.pyに飛びます。

そして、api/urls.pyでは、image/ というパスに対して、ImageFileViewというviewの処理へ促すようルーティングしています。

Viewの実装

先程のルーティングでimage/ に対してのルーティングが完了したので、このままimage/ が来たときのViewの処理を実装します。

/server/api/views.pyを編集します。

from django.shortcuts import render
from rest_framework import status, generics, permissions
from .models import *
from .serializers import *

class ImageFileView (generics.ListCreateAPIView):
    permission_classes = (permissions.AllowAny,)
    queryset = UploadFile.objects.all()
    serializer_class = UploadFileSerializer

ここでは、Django REST frameworkのgenerics.ListCreateAPIViewを使用してViewの処理を記述しています。

こちらのViewは、HTTPメソッドがGET or POST で来た場合、GET なら該当Modelのデータを返却し、POST なら、該当Modelにデータを登録してくれます。

詳しい仕様は、公式ドキュメントを参考にしてみてください。

該当Modelとは、後述するUploadFileModelになります。

Modelの定義

Viewの処理の実装が完了したので、続いてModelの定義を行っていきます。

from django.db import models
import os

def upload_image (instance, filename):
    return 'images/{0}/'.format(filename)

class UploadFile (models.Model):
    file = models.ImageField('画像ファイル', upload_to=upload_image)

    def __str__ (self):
        return self.file.url

    @property
    def filename (self):
        return os.path.basename(self.file.name)

ここでは、「file」名前のという画像専用のフィールドを用意しています。
upload_toには、データ登録時の保存先のパスを指定しています。
@propertyにて、新たに当Modelにプロパティを追加することで、画像名の取得を容易にしています。

Serializerの定義

続いて、Serializerを定義していきます。Serializerは、データの入出力を扱い、それをモデルに渡してくれるためのものです。

from rest_framework import serializers
from .models import *

class UploadFileSerializer (serializers.ModelSerializer):
    file = serializers.ImageField()
    file_name = serializers.SerializerMethodField()

    class Meta:
        model = UploadFile
        fields = '__all__'

    def get_file_name (self, obj):
        return obj.filename

migrationとmigrate

ここまでの実装が完了したら、Modelの変更点等を反映するために、一度マイグレーションとマイグレートを行います。

$ python manage.py makemigrations api
$ python manage.py migrate

動作確認

ここまでで、すべての実装は完了です。動作確認をするため、client、server両方のサーバを起動して、実際に画面からファイルをUploadしてみます。

無事にUploadが完了したら、server/media/imageディレクトリ内に、アップロードした画像が保存されていることが確認できるかと思います。

ディレクトリ構成

ここまでの作業が完了したら、下記のようなディレクトリ構成になっているかと思います。

├── client
│   ├── Dockerfile
│   └── img_uploader
│       ├── package.json
│       ├── public
│       │   ├── favicon.ico
│       │   ├── index.html
│       │   ├── manifest.json
│       │   └── robots.txt
│       ├── src
│       │   ├── App.css
│       │   ├── App.test.tsx
│       │   ├── App.tsx
│       │   ├── assets
│       │   │   └── image
│       │   │       └── upload_bg.jpg
│       │   ├── index.css
│       │   ├── index.tsx
│       │   ├── react-app-env.d.ts
│       │   ├── reportWebVitals.ts
│       │   └── setupTests.ts
│       ├── tsconfig.json
│       └── yarn.lock
├── docker-compose.yml
└── server
    ├── api
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── migrations
    │   │   ├── 0001_initial.py
    │   │   └── __init__.py
    │   ├── models.py
    │   ├── serializers.py
    │   ├── tests.py
    │   ├── urls.py
    │   └── views.py
    ├── db.sqlite3
    ├── manage.py
    ├── media
    │   └── images
    │       └── back_vOylmoT.jpg # アップロードされた画像ファイル
    └── server
        ├── __init__.py
        ├── asgi.py
        ├── settings.py
        ├── urls.py
        └── wsgi.py

実際のコードはこちらになります。

https://github.com/yoshihiko555/img-uploader

まとめ

今回は全3回に渡って、React × DRFを用いた簡単な画像アップロードアプリを作成してみました。拙い文章が多い中最後まで読んでくださった方には感謝です。

Django REST frameworkを用いることで、非常に簡単にRESTAPIの作成が可能です。Reactに関してはまだまだ、スキル不足な部分が多いので、もっと邁進していきたいと感じました。

Comments