PR

Django、React、MySQLを使ったMVP開発:機能追加と検証の手順、開発方法、閉じ方や終了方法

本記事では、Django(バックエンド)、React(フロントエンド)、MySQL(データベース)を使用してMVP(最小限の実用的製品)を開発する際の、機能追加、検証、開発方法、開発終了の手順を解説します。これにより、効率的な開発フローを確立し、最終的な製品がユーザーの期待を満たすことを目指します。

1. プロジェクトのセットアップ

開発環境の構築

まずはプロジェクトの開発環境を準備します。

Docker Composeを利用した環境構築

Docker Composeを使うことで、開発環境の構築を簡単に行えます。以下にdocker-compose.ymlの例を示します:

version: '3.8'

services:
  db:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
      interval: 5s
      timeout: 5s
      retries: 5

  backend:
    build:
      context: ./backend
    command: >
      sh -c "python manage.py migrate &&
             ./wait-for-it.sh db:3306 -- python manage.py runserver 0.0.0.0:8000"
    volumes:
      - ./backend:/app
    ports:
      - "8000:8000"
    environment:
      - DATABASE_HOST=db
      - DATABASE_NAME=${MYSQL_DATABASE}
      - DATABASE_USER=${MYSQL_USER}
      - DATABASE_PASSWORD=${MYSQL_PASSWORD}
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/admin"]
      interval: 10s
      timeout: 5s
      retries: 3

  frontend:
    build:
      context: ./frontend
    command: npm start
    volumes:
      - ./frontend:/app
      - /app/node_modules
    ports:
      - "3000:3000"
    environment:
      - REACT_APP_API_URL=http://localhost:8000
      - CHOKIDAR_USEPOLLING=true
    depends_on:
      - backend

volumes:
  mysql_data:
環境変数ファイル(.env

以下のような.envファイルをプロジェクトのルートに作成します。これにより、認証情報や接続設定がコードベースから分離され、セキュリティが向上します。

# .env
MYSQL_ROOT_PASSWORD=root_password
MYSQL_DATABASE=mvp_db
MYSQL_USER=mvp_user
MYSQL_PASSWORD=mvp_password

バックエンドのセットアップ

backendディレクトリ内にDockerfileを作成します:

FROM python:3.9

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

requirements.txtには必要なパッケージを記述します:

Django==4.0.0
djangorestframework==3.13.0
mysqlclient==2.1.0
django-cors-headers==3.10.0

フロントエンドのセットアップ

frontendディレクトリ内にDockerfileを作成します:

FROM node:16

WORKDIR /app

COPY package.json .
COPY package-lock.json .
RUN npm install

COPY . .

CMD ["npm", "start"]

プロジェクト初期化

Docker環境が構築されたら、Djangoプロジェクトとアプリ、そしてReactアプリを初期化します。

Djangoプロジェクトの初期化

docker-compose run backend django-admin startproject config .
docker-compose run backend python manage.py startapp api

Reactアプリの初期化

docker-compose run frontend npx create-react-app .

2. バックエンド (Django) の機能追加手順

モデルの定義

まず、データベースのスキーマを定義するためのモデルを作成します。api/models.pyを編集して、必要なモデルを定義します:

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    def __str__(self):
        return self.name

class User(models.Model):
    username = models.CharField(max_length=50, unique=True)
    email = models.EmailField(unique=True)
    created_at = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        return self.username

モデルを定義したら、マイグレーションを実行してデータベースに反映させます:

docker-compose run backend python manage.py makemigrations
docker-compose run backend python manage.py migrate

シリアライザの作成

REST APIでデータをJSON形式で送受信するために、シリアライザを定義します。api/serializers.pyを作成します:

from rest_framework import serializers
from .models import Product, User

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = '__all__'

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'

ビューの実装

データを操作するためのAPIビューを実装します。api/views.pyを編集します:

from rest_framework import viewsets
from .models import Product, User
from .serializers import ProductSerializer, UserSerializer

class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

URLの設定

APIエンドポイントを定義するために、URLを設定します。api/urls.pyを作成します:

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ProductViewSet, UserViewSet

router = DefaultRouter()
router.register(r'products', ProductViewSet)
router.register(r'users', UserViewSet)

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

メインのconfig/urls.pyも編集して、APIのURLを含めます:

from django.contrib import admin
from django.urls import path, include

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

DjangoとMySQLの接続設定

config/settings.pyを編集して、MySQLデータベースへの接続を設定します:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mvp_db',
        'USER': 'mvp_user',
        'PASSWORD': 'mvp_password',
        'HOST': 'db',
        'PORT': '3306',
    }
}

また、CORSの設定も追加して、フロントエンドからのAPIリクエストを許可します:

INSTALLED_APPS = [
    # ...
    'rest_framework',
    'corsheaders',
    'api',
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    # ...
]

CORS_ALLOWED_ORIGINS = [
    "http://localhost:3000",
]

3. フロントエンド (React) の機能追加手順

APIとの通信設定

まず、バックエンドAPIと通信するための設定を行います。src/api/index.jsを作成します:

import axios from 'axios';

const API_URL = 'http://localhost:8000/api';

const api = axios.create({
  baseURL: API_URL,
  headers: {
    'Content-Type': 'application/json',
  },
});

export const getProducts = () => api.get('/products/');
export const getProduct = (id) => api.get(`/products/${id}/`);
export const createProduct = (data) => api.post('/products/', data);
export const updateProduct = (id, data) => api.put(`/products/${id}/`, data);
export const deleteProduct = (id) => api.delete(`/products/${id}/`);

export const getUsers = () => api.get('/users/');
export const getUser = (id) => api.get(`/users/${id}/`);
export const createUser = (data) => api.post('/users/', data);
export const updateUser = (id, data) => api.put(`/users/${id}/`, data);
export const deleteUser = (id) => api.delete(`/users/${id}/`);

export default api;

コンポーネントの作成

次に、必要なコンポーネントを作成します。以下は商品一覧を表示するコンポーネントの例です。

src/components/ProductList.js

import React, { useState, useEffect } from 'react';
import { getProducts, deleteProduct } from '../api';
import { Link } from 'react-router-dom';

const ProductList = () => {
  const [products, setProducts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchProducts = async () => {
      try {
        const response = await getProducts();
        setProducts(response.data);
        setLoading(false);
      } catch (err) {
        setError('商品データの取得に失敗しました');
        setLoading(false);
      }
    };

    fetchProducts();
  }, []);

  const handleDelete = async (id) => {
    if (window.confirm('本当に削除しますか?')) {
      try {
        await deleteProduct(id);
        setProducts(products.filter(product => product.id !== id));
      } catch (err) {
        setError('商品の削除に失敗しました');
      }
    }
  };

  if (loading) return <div>読み込み中...</div>;
  if (error) return <div>{error}</div>;

  return (
    <div>
      <h2>商品一覧</h2>
      <Link to="/products/new">新規作成</Link>
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>商品名</th>
            <th>価格</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          {products.map(product => (
            <tr key={product.id}>
              <td>{product.id}</td>
              <td>{product.name}</td>
              <td>{product.price}円</td>
              <td>
                <Link to={`/products/${product.id}`}>詳細</Link>
                <Link to={`/products/${product.id}/edit`}>編集</Link>
                <button onClick={() => handleDelete(product.id)}>削除</button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

export default ProductList;

ルーティングの設定

React Routerを使用して、アプリケーションのルーティングを設定します。

src/App.js

import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Navbar from './components/Navbar';
import Home from './components/Home';
import ProductList from './components/ProductList';
import ProductDetail from './components/ProductDetail';
import ProductForm from './components/ProductForm';
import UserList from './components/UserList';
import UserDetail from './components/UserDetail';
import UserForm from './components/UserForm';

function App() {
  return (
    <Router>
      <div className="App">
        <Navbar />
        <div className="container">
          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/products" element={<ProductList />} />
            <Route path="/products/new" element={<ProductForm />} />
            <Route path="/products/:id" element={<ProductDetail />} />
            <Route path="/products/:id/edit" element={<ProductForm />} />
            <Route path="/users" element={<UserList />} />
            <Route path="/users/new" element={<UserForm />} />
            <Route path="/users/:id" element={<UserDetail />} />
            <Route path="/users/:id/edit" element={<UserForm />} />
          </Routes>
        </div>
      </div>
    </Router>
  );
}

export default App;

4. データベース (MySQL) の操作と検証

データベース接続の確認

開発中、データベース接続が正常に機能しているか確認することが重要です。以下のコマンドでMySQLサーバーに直接接続できます:

docker-compose exec db mysql -u mvp_user -p mvp_db

パスワードを入力すると、MySQLコンソールが起動します。

データベースクエリの実行

テーブル一覧を確認するには:

SHOW TABLES;

テーブルのスキーマを確認するには:

DESCRIBE api_product;
DESCRIBE api_user;

テーブル内のデータを確認するには:

SELECT * FROM api_product;
SELECT * FROM api_user;

Djangoシェルを使用したデータ操作

Django管理シェルを使用して、Pythonからデータベースを操作することもできます:

docker-compose exec backend python manage.py shell

シェル内で以下のようにモデルを操作できます:

from api.models import Product

# 新しい商品を作成
product = Product.objects.create(
    name="テスト商品",
    description="これはテスト商品です",
    price=1000
)

# 商品を取得して表示
products = Product.objects.all()
for p in products:
    print(f"{p.id}: {p.name} - {p.price}円")

# 商品を更新
product = Product.objects.get(id=1)
product.price = 1500
product.save()

# 商品を削除
product.delete()

5. 機能追加の検証手順

単体テスト

機能を追加した後は、単体テストを実行して正しく動作するか確認します。

バックエンドのテスト例(api/tests.py):

from django.test import TestCase
from django.urls import reverse
from rest_framework.test import APIClient
from rest_framework import status
from .models import Product

class ProductTests(TestCase):
    def setUp(self):
        self.client = APIClient()
        self.product_data = {
            'name': 'テスト商品',
            'description': 'これはテスト商品です',
            'price': '1000.00'
        }
        self.product = Product.objects.create(**self.product_data)

    def test_get_all_products(self):
        response = self.client.get(reverse('product-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertTrue(len(response.data) > 0)

    def test_create_product(self):
        new_product = {
            'name': '新商品',
            'description': '新しいテスト商品です',
            'price': '2000.00'
        }
        response = self.client.post(reverse('product-list'), new_product, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Product.objects.count(), 2)

テストを実行するには:

docker-compose exec backend python manage.py test

統合テスト

バックエンドとフロントエンドの連携をテストするために、以下の手順を実行します:

  1. バックエンドとフロントエンドを起動します: docker-compose up
  2. フロントエンドのテストを実行します: docker-compose exec frontend npm test
  3. ブラウザを開いてhttp://localhost:3000にアクセスし、機能が正しく動作するか手動でテストします。

手動テスト

開発中は定期的に手動テストを行い、以下の点を確認します:

  1. 新規データの作成
  2. データの読み取り
  3. データの更新
  4. データの削除
  5. バリデーションの動作
  6. エラー処理
  7. ユーザーインターフェースの使いやすさ

6. 開発終了時の作業とデプロイ方法

本番環境用の設定

本番環境用の設定を行います。

Djangoの本番設定(config/settings_prod.py):

from .settings import *

DEBUG = False
ALLOWED_HOSTS = ['your-domain.com']

# セキュリティ設定
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

# 静的ファイル設定
STATIC_ROOT = '/var/www/static/'

ビルドとデプロイ

フロントエンドのビルド

本番環境用のReactアプリをビルドします:

docker-compose exec frontend npm run build

本番環境用のDockerファイル

本番環境用のdocker-compose.prod.yml

version: '3'

services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql
    restart: always

  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile.prod
    command: gunicorn config.wsgi:application --bind 0.0.0.0:8000
    volumes:
      - static_volume:/app/static
    depends_on:
      - db
    env_file:
      - .env
    restart: always

  nginx:
    image: nginx:1.21
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/ssl:/etc/nginx/ssl
      - static_volume:/var/www/static
      - ./frontend/build:/var/www/frontend
    depends_on:
      - backend
    restart: always

volumes:
  mysql_data:
  static_volume:

バックエンドの本番用Dockerfile(backend/Dockerfile.prod):

FROM python:3.9

WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

RUN pip install --upgrade pip

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

RUN python manage.py collectstatic --noinput

EXPOSE 8000

CMD ["gunicorn", "--bind", "0.0.0.0:8000", "config.wsgi:application"]

デプロイ手順

  1. 環境変数ファイル(.env)を作成し、必要な値を設定します: DB_NAME=mvp_db_prod DB_USER=mvp_user_prod DB_PASSWORD=secure_password DB_ROOT_PASSWORD=root_secure_password DJANGO_SETTINGS_MODULE=config.settings_prod SECRET_KEY=your_secret_key
  2. 本番環境用のコンテナをビルドして起動します: docker-compose -f docker-compose.prod.yml build docker-compose -f docker-compose.prod.yml up -d
  3. データベースのマイグレーションを実行します: docker-compose -f docker-compose.prod.yml exec backend python manage.py migrate

開発終了後の手順

  1. コードの整理とリファクタリング
    • 使っていないコードの削除
    • コメントの追加
    • コードのフォーマット
  2. ドキュメントの作成
    • API仕様書
    • 使用方法ガイド
    • インストール手順
  3. バックアップの作成 docker-compose exec db mysqldump -u mvp_user -p mvp_db > backup.sql
  4. 継続的インテグレーションとデプロイの設定(CI/CD)
    • GitHubアクションやJenkinsなどのCI/CDツールを設定
    • テスト、ビルド、デプロイの自動化

まとめ

Django、React、MySQLを使ったMVP開発では、バックエンドAPI、フロントエンドコンポーネント、データベース操作を統合し、最小限の機能を迅速に開発することができます。機能追加後はテストを実施し、手動での検証やユニットテストを通じて品質を確保します。開発が終了した後は、Dockerを利用して本番環境にデプロイし、ユーザーに届けます。この流れを実践することで、効果的にMVPを開発し、リリースに至ることができます。

本記事で解説した手順は、MVPの段階から始まる製品開発の基礎となります。ユーザーフィードバックを収集し、継続的に改善していくことで、より価値のある製品へと発展させていくことが可能です。

コメント

タイトルとURLをコピーしました