この記事はDjangoプロジェクト内にReactを組み込んで開発するための環境構築をすることについて記述する.実行時にはDockerコンテナを使って最終的には"Hello World!"の表示と,データベースからデータを取り出すことを目標とする.その後,herokuにデプロイすることも行う.
今回の完成したコードをgithubに公開している
https://github.com/tarakokko3233/QiitaExample_WebApp_React-Django
DjangoとReactの連携
Djangoプロジェクトの作成
プロジェクトのルートディレクトリを作成.
$ mkdir yourprojectname
作成したディレクトリに移動する.
$ cd yourprojectname
環境構築用にPython仮想環境の構築を行う.
$ python3 -m venv venv
また,node.jsがインストールされていないのならば,このタイミングでインストールすること.
https://nodejs.org
Node.jsがインストールされているかどうかの確認方法は
$ npm
で表示されればOK
仮装環境を起動する.
Mac
$ source venv/bin/activate
Windows
$ venv\Scripts\activate
のちに実行時にはDockerコンテナを使用して立ち上げるので仮の仮想環境だと思って欲しい.
仮装環境に必要なライブラリをインストールする.
$ pip install django djangorestframework
Dockerコンテナ用にどのライブラリをインストールするかを記述するrequirements.txt
を作成する.
$ touch requirements.txt
requirements.txt
に以下のライブラリを記述する.
asgiref
Django
djangorestframework
sqlparse
開発中に他のPythonライブラリが必要になったらrequirements.txtに追記すること.
Djangoのプロジェクトを作る.
$ django-admin startproject yourprojectname
作成したDjangoプロジェクトに移動する.
$ cd yourprojectname
次にDjangoプロジェクト上でReact開発用のDjangoアプリを作成する.
$ django-admin startapp frontend
アプリの名前はfrontendにしたが実際はなんでもいい.後の設定のfrontendの部分を変更することを忘れないように
settings.py
のINSTALLED_APPS
に必要なアプリを追加する.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', # これと
'frontend', # これを追加する
]
settings.py
のALLOWED_HOSTS
以下のコードを追加する.
ALLOWED_HOSTS = ['localhost',
'127.0.0.1']
この時点でデータベースにデフォルトのテーブルを適用する.
$ python manage.py migrate
Reactのコードを入れるためのディレクトリを作成
この章ではカレントディレクトリをyourprojectname
(ルートディレクトリ)で実行すること
Reactで作成したコードを表示するためのテンプレートを格納するためのディレクトリを作成する.
$ mkdir frontend/templates
静的ファイル(CSS,画像,main.js)格納用のディレクトリを作成する.
$ mkdir frontend/static
わかりやすいように用途ごとにディレクトリを作成する.
$ mkdir frontend/static/frontend
$ mkdir frontend/static/css
$ mkdir frontend/static/images
Reactのコードを入れるためのディレクトリを作成する.
$ mkdir frontend/src
$ mkdir frontend/src/components
node.jsのモジュールをインストール
この章ではカレントディレクトリをfrontend
で実行すること.
$ cd frontend
はじめにNodeプロジェクトを初期化する.
$ npm init -y
複数のJavaScriptライブラリを一つにまとめるためのwebpackをインストールする.
$ npm i webpack webpack-cli --save-dev
npm i
はnpm install
のこと,-save-devオプションは、モジュールをローカルインストールするためのオプション
JavaScriptの最新バージョンでは最新の構文が登場するが,その構文は古いブラウザでは動作しないことがあるため,最新の構文を古いブラウザでも動くように変換するツールであるbabelをインストールする.
$ npm i @babel/core babel-loader @babel/preset-env @babel/preset-react --save-dev
$ npm i @babel/plugin-proposal-class-properties
最後にReactをインストールする.
$ npm i react react-dom --save-dev
$ npm i react-router-dom
node.jsモジュールの設定ファイルのセットアップ
webpackのconfigファイルを作成する.
$ touch webpack.config.js
webpack.config.js
に以下の内容を記述する.
const path = require("path");
const webpack = require("webpack");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "./static/frontend"),
filename: "[name].js",
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
],
},
optimization: {
minimize: true,
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV' : JSON.stringify('production')
})
]
}
次に,babelのconfigファイルを作成する.
$ touch babel.config.json
babel.config.json
に以下の内容を記述する.
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "14"
}
}
],
"@babel/preset-react"
],
"plugins": ["@babel/plugin-proposal-class-properties"]
}
Reactのエントリーポイントであるindex.js
を作成する.
$ touch src/index.js
最後にpackage.json
の"scripts"
を以下の内容に変更する.
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack --mode development --watch",
"build": "webpack --mode production"
}
package.json
において,もし
"@babel/plugin-proposal-class-properties"
が"dependencies":
にあるときは,"devDependencies":
に記述すること.
package.json
はこのようになっているはずである.package.json{ "name": "frontend", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack --mode development --watch", "build": "webpack --mode production" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "@babel/core": "^7.24.4", "@babel/preset-env": "^7.24.4", "@babel/preset-react": "^7.24.1", "babel-loader": "^9.1.3", "react": "^18.3.1", "react-dom": "^18.3.1", "webpack": "^5.91.0", "webpack-cli": "^5.1.4", "@babel/plugin-proposal-class-properties": "^7.18.6" }, "dependencies": { "react-router-dom": "^6.23.0" } }
テンプレートの作成
この章ではカレントディレクトリをfrontend
で実行すること.
Reactのコードを表示するためのテンプレートを作成する.
$ mkdir templates/frontend
$ touch templates/frontend/index.html
index.heml
を以下のように記述する.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
{% load static %}
</head>
<body>
<div id="main">
<div id="app"></div>
</div>
<script src="{% static "frontend/main.js" %}"></script>
</body>
</html>
もしCSSファイルを作成するのならば以下のコードをheadタグの一番最後に記述する.
index.html<!-- cssを追加する場合 --> <link rel="stylesheet" href="{% static "css/index.css" %}">
簡単にReactのコードを書く.frontend/src/components/App.js
を作成する.
$ touch src/components/App.js
import React, { Component } from "react"
import { render } from "react-dom"
export default class App extends Component {
constructor(props) {
super(props);
}
render() {
return <h1>Hello World!</h1>;
}
}
const appDiv = document.getElementById("app");
render(<App/>, appDiv)
ビューとエンドポイントの作成
yourprojectname/frontend/views.py
に以下のビューを追加する.
def index(request, *args, **kwargs):
return render(request, 'frontend/index.html')
yourprojectname/yourprojectname/urls.py
に以下のビューを作成する.
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('frontend.urls')),
]
frontend
ディレクトリ内にurls.pyを作成する.
$ touch urls.py
作成したfrontend/urls.py
を以下のように編集する.
from django.urls import path
from .views import index
urlpatterns = [
path('', index)
]
最後にindex.js
でApp.js
を読み込むようにする.
import App from "./components/App";
これで完成である.
Dockerコンテナの作成
この章ではカレントディレクトリをyourprojectname
(ルートディレクトリ)で実行すること
yourprojectname
ディレクトリ(ルートディレクトリ)でDockerfileを作成する.
$ touch Dockerfile
# Node.jsの公式イメージを使用
FROM node:14 as build
# 作業ディレクトリの設定
WORKDIR /app/frontend
# package.jsonとpackage-lock.jsonをコピー
COPY frontend/package*.json ./
# Node.jsの依存パッケージをインストール
RUN npm install
# 残りのフロントエンドファイルをコピー
COPY frontend/ .
# Djangoアプリ用のイメージをベースに
FROM python:3.9
# 作業ディレクトリの設定
WORKDIR /app
# 必要なパッケージをインストール
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 残りのファイルをコピー
COPY . .
# データベースファイルを永続化するためのボリュームを作成
VOLUME /app/db_data
# ポートの公開
EXPOSE 8000
# Djangoアプリの起動コマンド
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
yourprojectname
ディレクトリ(ルートディレクトリ)でdocker-compose.yml
を作成する.
$ touch docker-compose.yml
services:
backend:
build: .
ports:
- 8000:8000
volumes:
- .:/app
- db_data:/app/db_data
frontend:
build:
context: ./frontend
dockerfile: Dockerfile.dev
volumes:
- ./frontend:/app
ports:
- 3000:3000
volumes:
db_data:
yourprojectname/frontend
ディレクトリでDockerfile.dev
を作成する.
$ touch frontend/Dockerfile.dev
# Node.jsの公式イメージを使用
FROM node:14
# 作業ディレクトリの設定
WORKDIR /app
# package.jsonとpackage-lock.jsonをコピー
COPY package*.json ./
# Node.jsの依存パッケージをインストール
RUN npm install
# ソースコードをコピー
COPY . .
# ホットリロードサーバーを起動
CMD ["npm", "run", "dev"]
これでyourprojectname
ディレクトリ(ルートディレクトリ)において,以下のコマンドを実行すればDockerコンテナをビルド&立ち上げができる.
$ docker compose up
この時点でdockerコンテナを用いて実行をするので最初に作成したPython仮装環境であるvenvファイルは不要である.削除してよい.
Dockerコンテナをうまく立ち上げられなかった場合
ターミナル(コマンドプロンプト,WindowsPowerShell)を2つ立ち上げる.
1つはルートディレクトリでPython仮装環境を起動したことを確認して以下のコマンドを実行する.$ python manage.py runserver
もう1つは
frontend
ディレクトリで以下のコマンドを実行する.$ npm run dev
サーバーを立ち上げたら,http://localhost:8000 にアクセスする.アクセスしたら左上にHello World!と表示されていたらOK
つぎはデータのやり取りをDjangoとReactでするための設定をする
データベースからデータを取得する
ここからはデータベースからデータを受信してテンプレートに表示する方法について記述する.今回はUsers(id,name,email)モデルを作成し,nameとemailを表示する.
モデル,ビュー,エンドポイントの作成
この章ではカレントディレクトリをfrontend
ディレクトリで実行する
$ cd frontend
frontend
ディレクトリでモデルを作成する.
from django.db import models
class Users(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
コンテナを立ち上げた状態(docker compose up
)で以下のコマンドを実行する.これでマイグレーションファイルを作成し,データベースに適用する.
$ docker compose exec backend python manage.py makemigrations
$ docker compose exec backend python manage.py migrate
Dockerが使えない場合は仮装環境を立ちあげて以下のコマンドを実行する.
$ python manage.py makemigrations $ python manage.py migrate
frontend
ディレクトリでserializers.py
を作成する.
$ touch serializers.py
from rest_framework import serializers
from .models import Users
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = Users
fields = ['id', 'name', 'email']
frontend
ディレクトリのviews.py
に追記する.
from django.shortcuts import render
from rest_framework import viewsets
from .serializers import UserSerializer
from .models import Users
# Create your views here.
def index(request, *args, **kwargs):
return render(request, 'frontend/index.html')
class UserViewSet(viewsets.ModelViewSet):
queryset = Users.objects.all()
serializer_class = UserSerializer
frontend
ディレクトリのurls.py
を以下のように変更する.
from django.urls import path
from .views import index
from rest_framework import routers
from .views import UserViewSet
router = routers.DefaultRouter()
router.register('api/users', UserViewSet)
urlpatterns = [
path('', index, name='frontend')
]+ router.urls
React側でJavaScriptでデータ表示する
この章ではカレントディレクトリをyourprojectname
(ルートディレクトリ)で実行する
frontend/src/components
ディレクトリにUsersList.js
を作成する.
$ touch frontend/src/components/UsersList.js
// UsersList.js
import React, { useState, useEffect } from 'react';
const UsersList = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
const fetchUsers = async () => {
const response = await fetch('api/users/');
const data = await response.json();
setUsers(data);
};
fetchUsers();
}, []);
return (
<div>
<h1>UsersList</h1>
<ul>
{users.map((user) => (
<li key={user.id}>
{user.name} - {user.email}
</li>
))}
</ul>
</div>
);
};
export default UsersList;
frontend/src/components/App.js
でUserList.js
に遷移するようのリンクを設定する.
// App.js
import React from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter as Router, Route, Link, Routes } from 'react-router-dom';
import UsersList from './UsersList';
const App = () => {
return (
<Router>
<div>
<h1>Hello World!</h1>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/users">Users</Link>
</li>
</ul>
</nav>
<Routes>
<Route path="/users" element={<UsersList />} />
</Routes>
</div>
</Router>
);
};
const container = document.getElementById('app');
const root = createRoot(container);
root.render(<App />);
今回はUsersList.jsへのエンドポイントは
/users
とする
この時点で試しにdb.sqlite3
へデータを挿入すること.
データベースにアクセスするGUIソフトウェアをインストールしておくとSQliteなどデータベースを管理しやすい.
例えばTablePlusというソフトウェアがある.
https://tableplus.com
リモートやローカルのPostgreSQLやMySQLにアクセスしてもよいがその時はsettings.py
のDATABASE設定を変更すること
たとえばDBサーバとしてHerokuPostgresを使う場合の設定は以下の記事を参照すること
https://qiita.com/tarakokko3233/items/0961933e2b9695cb561a
ただし上記の記事はデプロイの仕方まで記載してあるが,今回は上記の記事の仕方でデプロイ出来ないので注意すること
データベース接続情報を直接
settings.py
に書き込むことはセキュリティ上危険なので以下の記事を参考にして環境変数を使用して欲しい
https://qiita.com/tarakokko3233/items/bb63dbef9d91f44d3917
これでyourprojectname
ディレクトリ(ルートディレクトリ)において,以下のコマンドを実行すればDockerコンテナをビルド&立ち上げができる.
$ docker compose up
再掲
Dockerコンテナをうまく立ち上げられなかった場合
ターミナル(コマンドプロンプト,WindowsPowerShell)を2つ立ち上げる.
1つはルートディレクトリでPython仮装環境を起動したことを確認して以下のコマンドを実行する.$ python manage.py runserver
もう1つは
frontend
ディレクトリで以下のコマンドを実行する.$ npm run dev
サーバーを立ち上げたら,http://localhost:8000 にアクセスする.
PaaSにデプロイする
今回はHerokuにデプロイする.
静的ファイルの収集とALLOWED_HOSTSの追加
settings.py
に静的ファイルを収集するための設定を追記する.
import os
ALLOWED_HOSTS = ['localhost',
'127.0.0.1',
'.herokuapp.com' ] #この行を追加
MIDDLEWARE = [
# 他のミドルウェア...
'whitenoise.middleware.WhiteNoiseMiddleware', #これを追加
]
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'frontend', 'build', 'static'),
]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
WhitenoiseのApacheDeployHandler設定を追加するために,wsgi.py
を変更する.
# wsgi.py
import os
from django.core.wsgi import get_wsgi_application
from whitenoise import WhiteNoise
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'yourprojectname.settings')
application = get_wsgi_application()
application = WhiteNoise(application)
requirements.txtへの追記
デプロイ用のPythonライブラリをrequirements.txt
に追記する.
asgiref
Django
django-environ
gunicorn
psycopg2
djangorestframework
django-filter
whitenoise
dj-database-url
runtime.txtの作成
デプロイ時のwebサーバで使うpythonバージョンを指定するファイルをyourprojectname
ディレクトリ(ルートディレクトリ)に追加する
python-3.12.2
Procfileの作成
HerokuでDjangoアプリケーションをデプロイする際に,Herokuがアプリケーションをどのように実行すべきかを指示するファイルをyourprojectname
ディレクトリ(ルートディレクトリ)に追加する
web: gunicorn yourprojectname.wsgi --log-file -
react-build: npm install --prefix frontend
react-build: npm run build --prefix frontend
release: python manage.py migrate
ここまでのファイルをgitにプッシュする.プッシュする際にリポジトリに.gitignoreを追加することをお勧めする.
# Python
*.pyc
*~
__pycache__
# Database
db.sqlite3
# Static files
static/
# Media files
media/
# Environment
.env
.venv
env/
# Node
node_modules/
npm-debug.log
# OS files
.DS_Store
Thumbs.db
# Editor files
.vscode/
.idea/
この状態でherokuアプリケーションにプッシュしたgitリポジトリを接続してデプロイする.
herokudashboardの使い方については以下の記事を参考にすること
https://qiita.com/tarakokko3233/items/0961933e2b9695cb561a
上記の記事ではデプロイするためのファイルは今回とは異なるので注意
お疲れ様でした.