Django + React + MySQL を使った MVP 開発ガイド【Dockerを活用】
はじめに
本記事では、Python (Django)、React、MySQL を使って、簡単な MVP(最小限の実行可能な製品)を作成する方法をステップバイステップで解説します。この構成は、Web アプリケーションを開発するための一般的なフレームワークであり、バックエンドとフロントエンドを分けて開発するモダンなアーキテクチャを採用しています。
使用する技術
- バックエンド: Python, Django, Django REST Framework
- フロントエンド: React
- データベース: MySQL
- コンテナ化ツール: Docker
- 環境: ローカル開発
必要な準備
- Python 3.9 以上
- Node.js と npm
- Docker と Docker Compose
- Git(バージョン管理用)
1. プロジェクトの構成
まずは、プロジェクトのディレクトリ構造を決めましょう。基本的な構成は次のようになります。
my-mvp-project/
├── backend/ # Django バックエンド
│ ├── Dockerfile
│ ├── requirements.txt
│ ├── .env.example # 環境変数のサンプル
│ └── (その他 Django のファイル)
├── frontend/ # React フロントエンド
│ ├── Dockerfile
│ ├── package.json
│ ├── .env.example # 環境変数のサンプル
│ └── (その他 React のファイル)
├── docker-compose.yml # Docker Compose 設定ファイル
├── .env # 環境変数(.gitignoreに追加)
└── README.md
2. Docker と Django のセットアップ
まずは、バックエンドの Django を Docker を使ってセットアップします。
2.1. Dockerfile の作成(Django 用)
backend ディレクトリ内に Dockerfile を作成します。これにより、Django アプリケーションをコンテナ内で実行できます。
# Python のベースイメージを指定
FROM python:3.9-slim
# 必要なパッケージをインストール
RUN apt-get update && apt-get install -y \
python3-dev \
libmariadb-dev \
pkg-config \
build-essential \
libssl-dev \
&& rm -rf /var/lib/apt/lists/*
# 作業ディレクトリの設定
WORKDIR /app
# requirements.txt をコピーしてインストール
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
# アプリケーションコードをコピー
COPY . /app/
# ポート 8000 を開放
EXPOSE 8000
# Django の開発サーバーを起動
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
2.2. requirements.txt の作成
次に、backend ディレクトリ内に requirements.txt を作成し、必要なパッケージを記述します。
Django>=4.0,<5.0
djangorestframework>=3.14.0
django-cors-headers>=4.0.0
mysqlclient>=2.1.0
python-dotenv>=1.0.0
2.3. Django プロジェクトの作成
Django プロジェクトを作成するには、次のコマンドを実行します。
mkdir -p backend
docker run --rm -v ${PWD}/backend:/app -w /app python:3.9-slim /bin/bash -c "pip install django && django-admin startproject core ."
これで、backend フォルダに Django プロジェクトが作成されます。次に、APIのためのアプリを作成します:
docker run --rm -v ${PWD}/backend:/app -w /app python:3.9-slim /bin/bash -c "pip install django && python manage.py startapp api"
2.4. Django の設定
次に、Django の設定ファイル settings.py
を編集します。backend/core/settings.py を以下のように修正します:
import os
from pathlib import Path
from dotenv import load_dotenv
# .env ファイルを読み込む
load_dotenv()
# ...既存の設定...
# シークレットキーを環境変数から読み込む
SECRET_KEY = os.getenv('DJANGO_SECRET_KEY', 'django-insecure-default-key-for-development')
# デバッグモードを環境変数から設定
DEBUG = os.getenv('DEBUG', 'True') == 'True'
# 許可するホストを設定
ALLOWED_HOSTS = ['localhost', '127.0.0.1', '0.0.0.0']
# インストールしたアプリケーションを追加
INSTALLED_APPS = [
# デフォルトのアプリケーション
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# サードパーティアプリケーション
'rest_framework',
'corsheaders',
# プロジェクトアプリケーション
'api',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # CORS ミドルウェアを追加(最初に配置)
# ...既存のミドルウェア...
]
# CORS の設定(開発環境では全てのオリジンを許可)
CORS_ALLOW_ALL_ORIGINS = DEBUG
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
"http://127.0.0.1:3000",
]
# ...既存の設定...
# データベースの設定
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': os.getenv('DB_NAME', 'mydb'),
'USER': os.getenv('DB_USER', 'root'),
'PASSWORD': os.getenv('DB_PASSWORD', 'password'),
'HOST': os.getenv('DB_HOST', 'db'),
'PORT': os.getenv('DB_PORT', '3306'),
}
}
# ...既存の設定...
# 静的ファイルの設定
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
# メディアファイルの設定
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# REST Framework の設定
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
],
}
2.5. サンプル API の作成
簡単な API を作成するために、以下のファイルを作成します。
backend/api/models.py
from django.db import models
class Task(models.Model):
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
completed = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
backend/api/serializers.py
from rest_framework import serializers
from .models import Task
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = '__all__'
backend/api/views.py
from rest_framework import viewsets
from rest_framework.permissions import AllowAny
from .models import Task
from .serializers import TaskSerializer
class TaskViewSet(viewsets.ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer
permission_classes = [AllowAny] # 開発用に認証を不要に設定
backend/core/urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from api.views import TaskViewSet
router = DefaultRouter()
router.register(r'tasks', TaskViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(router.urls)),
]
2.6. 環境変数ファイルの作成
backend ディレクトリに .env.example
ファイルを作成します:
DJANGO_SECRET_KEY=your_secret_key_here
DEBUG=True
DB_NAME=mydb
DB_USER=root
DB_PASSWORD=password
DB_HOST=db
DB_PORT=3306
3. React のセットアップ
3.1. React アプリの作成
frontend ディレクトリに React アプリケーションを作成します。
npx create-react-app frontend
3.2. Dockerfile の作成(React 用)
frontend ディレクトリ内に Dockerfile を作成します。
# Node.js のベースイメージを指定
FROM node:16-alpine
# 作業ディレクトリの設定
WORKDIR /app
# package.json と package-lock.json をコピー
COPY package*.json ./
# 依存パッケージをインストール
RUN npm install
# アプリケーションコードをコピー
COPY . /app/
# React の開発サーバーを起動
CMD ["npm", "start"]
3.3. API 連携のための設定
以下のパッケージをインストールします:
cd frontend
npm install axios
環境変数を管理するために .env
ファイルを作成します:
frontend/.env
REACT_APP_API_URL=http://localhost:8000/api
3.4. サンプルコンポーネントの作成
API と連携する簡単なコンポーネントを作成します:
frontend/src/components/TaskList.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:8000/api';
function TaskList() {
const [tasks, setTasks] = useState([]);
const [newTask, setNewTask] = useState({ title: '', description: '' });
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
// タスク一覧を取得
useEffect(() => {
const fetchTasks = async () => {
try {
setLoading(true);
const response = await axios.get(`${API_URL}/tasks/`);
setTasks(response.data);
setError(null);
} catch (err) {
setError('タスクの取得に失敗しました');
console.error(err);
} finally {
setLoading(false);
}
};
fetchTasks();
}, []);
// 新しいタスクを追加
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await axios.post(`${API_URL}/tasks/`, newTask);
setTasks([...tasks, response.data]);
setNewTask({ title: '', description: '' });
} catch (err) {
setError('タスクの追加に失敗しました');
console.error(err);
}
};
// タスク完了状態の切り替え
const toggleComplete = async (id, completed) => {
try {
const updatedTask = await axios.patch(`${API_URL}/tasks/${id}/`, {
completed: !completed
});
setTasks(tasks.map(task =>
task.id === id ? updatedTask.data : task
));
} catch (err) {
setError('タスクの更新に失敗しました');
console.error(err);
}
};
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div className="task-list">
<h2>タスク一覧</h2>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="タスク名"
value={newTask.title}
onChange={(e) => setNewTask({...newTask, title: e.target.value})}
required
/>
<textarea
placeholder="詳細"
value={newTask.description}
onChange={(e) => setNewTask({...newTask, description: e.target.value})}
/>
<button type="submit">追加</button>
</form>
<ul>
{tasks.map(task => (
<li key={task.id}>
<input
type="checkbox"
checked={task.completed}
onChange={() => toggleComplete(task.id, task.completed)}
/>
<span style={{ textDecoration: task.completed ? 'line-through' : 'none' }}>
{task.title}
</span>
<p>{task.description}</p>
</li>
))}
</ul>
</div>
);
}
export default TaskList;
frontend/src/App.js
import React from 'react';
import './App.css';
import TaskList from './components/TaskList';
function App() {
return (
<div className="App">
<header className="App-header">
<h1>Django + React タスク管理アプリ</h1>
</header>
<main>
<TaskList />
</main>
</div>
);
}
export default App;
4. Docker Compose の設定
4.1. docker-compose.yml の作成
プロジェクトのルートディレクトリに docker-compose.yml
ファイルを作成します:
version: '3.8'
services:
db:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD:-password}
MYSQL_DATABASE: ${DB_NAME:-mydb}
volumes:
- db_data:/var/lib/mysql
ports:
- "${DB_PORT:-3306}:3306"
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${DB_PASSWORD:-password}"]
backend:
build: ./backend
command: >
bash -c "
python manage.py wait_for_db &&
python manage.py migrate &&
python manage.py runserver 0.0.0.0:8000
"
volumes:
- ./backend:/app
ports:
- "8000:8000"
depends_on:
db:
condition: service_healthy
environment:
- DJANGO_SECRET_KEY=${DJANGO_SECRET_KEY:-django-insecure-default-key-for-development}
- DEBUG=${DEBUG:-True}
- DB_NAME=${DB_NAME:-mydb}
- DB_USER=${DB_USER:-root}
- DB_PASSWORD=${DB_PASSWORD:-password}
- DB_HOST=db
- DB_PORT=3306
frontend:
build: ./frontend
command: npm start
volumes:
- ./frontend:/app
- /app/node_modules
ports:
- "3000:3000"
depends_on:
- backend
environment:
- REACT_APP_API_URL=http://localhost:8000/api
- CHOKIDAR_USEPOLLING=true
volumes:
db_data:
5. データベース待機スクリプトの作成
Django アプリケーションが起動する前に MySQL が完全に起動していることを確認するためのカスタムコマンドを作成します。
backend/api/management/commands/wait_for_db.py
import time
from django.db import connections
from django.db.utils import OperationalError
from django.core.management.base import BaseCommand
class Command(BaseCommand):
"""Django コマンド: データベースが利用可能になるまで待機する"""
def handle(self, *args, **options):
self.stdout.write('データベースの起動を待機中...')
db_conn = None
while not db_conn:
try:
db_conn = connections['default']
self.stdout.write(self.style.SUCCESS('データベース接続成功!'))
except OperationalError:
self.stdout.write('データベースは利用できません、2秒後に再試行...')
time.sleep(2)
6. アプリケーションの起動
6.1. プロジェクトルートに .env
ファイルを作成
# Django 設定
DJANGO_SECRET_KEY=your_secret_key_here
DEBUG=True
# データベース設定
DB_NAME=mydb
DB_USER=root
DB_PASSWORD=mypassword
DB_PORT=3306
6.2. コンテナをビルドして起動
以下のコマンドで、全てのコンテナをビルドして起動します。
docker-compose up --build
これで、バックエンドは http://localhost:8000 で、フロントエンドは http://localhost:3000 でアクセスできるようになります。
6.3. 管理者ユーザーの作成
管理画面にアクセスするために、管理者ユーザーを作成します。
docker-compose exec backend python manage.py createsuperuser
指示に従ってユーザー名、メールアドレス、パスワードを設定します。作成後、http://localhost:8000/admin にアクセスして管理画面にログインできます。
7. 開発の進め方
7.1. バックエンド開発
- モデルの定義(
models.py
) - シリアライザーの作成(
serializers.py
) - ビューの実装(
views.py
) - URL パターンの設定(
urls.py
) - マイグレーションの作成と適用
docker-compose exec backend python manage.py makemigrations
docker-compose exec backend python manage.py migrate
7.2. フロントエンド開発
- コンポーネントの作成
- APIとの通信実装(Axios)
- ルーティング(React Router)
- スタイリング(CSS/SCSS)
7.3. テストの実施
バックエンドのテスト
docker-compose exec backend python manage.py test
フロントエンドのテスト
docker-compose exec frontend npm test
8. 本番環境へのデプロイ準備
8.1. バックエンドの本番設定
backend/core/settings.py に本番環境用の設定を追加します:
# 本番環境の設定
if not DEBUG:
# CSRFとセキュリティ設定
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
# 静的ファイルの設定
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
# CORSの設定
CORS_ALLOWED_ORIGINS = [
# 本番用フロントエンドのURLを指定
]
8.2. フロントエンドのビルド
本番デプロイのために React アプリをビルドします:
docker-compose exec frontend npm run build
9. まとめ
この記事では、Python (Django)、React、MySQL を使って MVP を構築する方法を紹介しました。Docker を使うことで開発環境を簡単にセットアップでき、バックエンドとフロントエンドを分けて開発することができます。
主なポイント:
- Docker を使った環境構築で開発の効率化
- Django REST Framework でのAPI開発
- React でのフロントエンド実装
- MySQL データベースの活用
- 本番環境へのデプロイ準備
この構成は様々なウェブアプリケーションの基盤として活用でき、拡張性も高いため、機能追加も容易に行えます。
次のステップ
- 認証機能の追加(JWT、OAuth など)
- テストの充実(単体テスト、統合テスト)
- CI/CD パイプラインの構築
- クラウドプラットフォームへのデプロイ(AWS、GCP、Azure など)
コメント