前書き
ReactとDjangoを連携したアプリを作成する手順です。
フロントエンドではTypescript、Tailwind CSSを使い、バックエンドではpythonを使用する。
本文は、使った技術の設定を中心に記載している。
1. Django(バックエンド)の基本設定
本文は https://qiita.com/shiranon/items/8182445975dff4cf19a6 (DjangoとReactの構築及びAPI連携について~構築編~) を一部参考した。
Djangoをインストールする
$ pip3 install django
rest_frameworkインストール
$ pip3 install djangorestframework
Djangoのプロジェクトを作成する
$ django-admin startproject <projectName>
本文ではプロジェクトの名前をbackendとする。なので、$ django-admin startproject backend
を実行する。
デフォルトのファイル
コマンドを実行すると、プロジェクトの名前でディレクトリが作成される。
その中身は以下の通り。(△は編集する必要があるもの)
projectName
├─ manage.py 【プロジェクト管理、App作成、データ管理など】
└─ projectName
├─ __init__.py
├─ settings.py 【△プロジェクトの構成】
├─ urls.py 【△URLを関数に対応】
├─ asgi.py 【リクエスト処理】
└─ wsgi.py 【リクエスト処理】
Appを作成する
$ python manage.py startapp <AppName>
本文ではAppの名前をAppとする。
その他に、Api作成用のAppも作成する。
なので、
$ python manage.py startapp app
$ python manage.py startapp api
を実行する。
デフォルトのファイル
コマンドを実行すると、Appの名前でディレクトリが作成される。
その中身は以下の通り。
App
├─ __init__.py
├─ admin.py 【デフォルトのadmin管理者】
├─ apps.py 【app起動】
├─ migrations 【DB変更記録】
| └─ __init__.py
├─ models.py 【△DBに対する操作】
├─ tests.py 【Unitテスト】
└─ views.py 【△関数】
APPを登録する
Appを作成したら、プロジェクトのsettings.pyに作成したAppを登録する必要がある。
ここで、rest_framework
も登録する。
settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app', #追加
'api.apps.ApiConfig', #追加
'rest_framework', #追加
]
URLとview関数との関係の設定
ブラウザからURLでウェブページを表示するには、URLとview関数との関係を設定する必要がある。
Appディレクトリでurls.pyを作成する。
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
プロジェクトのurls.pyを編集する。
from django.urls import include, path # includeを追加
urlpatterns = [
path('admin/', admin.site.urls), #デフォルトの管理者画面
path('app/', include('app.urls')),
]
Appのviews.pyを編集する。
from django.shortcuts import render, HttpResponse
def index(request):
return HttpResponse("Hello, world")
指定したurlにアクセスすると、viewsでの関数が呼び出されるという仕組みである。
ここではlocalhost:8000/index/
にアクセスすると、Hello, world
と表示されるようになる。
サーバー起動
manage.pyがあるディレクトリで、以下のコマンドを実行する。
$ python manage.py runserver 8000
デフォルトのポート番号は8000番なので、ポート番号を指定せずに$ python manage.py runserver
でも起動できるが。
ボート番号を指定したい場合は、$ python manage.py runserver <port番号>
のようにする。
これでDjangoの基本的な設定は完了した。
2. APIを作成する
データベースを準備する
具体的なDjangoでデータベースを操る方法はこちら:https://qiita.com/shintake_heito/private/6362c008004d97d3eeda
今回はAPI化したDBを準備する。
Appのmodels.pyを編集する。
from django.db import models
# Create your models here.
class User_Model(models.Model):
class Meta:
db_table = 'User'
user_id = models.CharField(
verbose_name='userid',
blank=True,
null=True,
max_length=225,
default='',
)
user_name = models.CharField(
verbose_name='username',
blank=True,
null=True,
max_length=225,
default='',
)
user_email = models.CharField(
verbose_name='useremail',
blank=True,
null=True,
max_length=225,
default='',
)
def __str__(self):
return self.user_id
ここで、user_id、user_name、user_emailの3つの項目を作成した。
manage.py
でmigrationを行う
$ python manage.py makemigrations
$ python manage.py migrate
管理画面からデータ投入を行うのでadmin.pyに記載する。
from django.contrib import admin
from .models import User_Model
admin.site.register(User_Model)
管理サイトに入るためのスーパーユーザ作成する。
python manage.py createsuperuser
スーパーユーザを作成したら、localhost:8000/admin/
にアクセスし、ログインする。
DBシリアライズ化の設定
次にDBのシリアライズ化を行う。
apiアプリフォルダにserializers.pyを作成し、以下のように記載する。
from rest_framework import serializers
from app.models import User_Model
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User_Model
fields = ('user_id', 'user_name','user_email')
apiアプリフォルダのviews.pyを以下のように記載する。
from rest_framework import viewsets, routers
from app.models import User_Model
from .serializers import UserSerializer
class UserApi(viewsets.ModelViewSet):
queryset = User_Model.objects.all()
serializer_class = UserSerializer
def get_queryset(self):
queryset = User_Model.objects.all()
L_id = self.request.query_params.get('id')
# queryでidを受けるとidでDBに検索をかけるようにしている。
if L_id:
queryset = queryset.filter(user_id=L_id)
return queryset
router = routers.DefaultRouter()
router.register(r'user', UserApi)
ルーティングの設定
プロジェクトのurls.pyを以下のように記載する。
from django.contrib import admin
from django.urls import include, path
from api import views as api_views
urlpatterns = [
path('admin/', admin.site.urls),
path('app/', include('app.urls')),
path('api/', include(api_views.router.urls)), #追加
]
これで、APIの準備は完了した。
runserver
し、http://localhost:8000/<apiアプリ>
にアクセスすると、DBのデータが表示される。
3. React(フロントエンド)の設定
Reactのプロジェクトを作成し、TailwindCSSを使用する。
Reactのプロジェクトを作成する
$ npm create-react-app <projectName>
本文ではプロジェクトの名前をfrontendとする。なので、$ npm create-react-app frontend
を実行する。
TypescriptベースのReactプロジェクトを作成
Typescriptを使用したReactプロジェクトを作成するには
create-react-app <projectName> --template typescript
コマンドを実行する
ここで、--template typescript
でtypescriptのテンプレートを指定する
TailwindCSSの使用
create-react-app
ではPostCSSの設定、postcss-importなどの重要なツールの設定に対応しないため、 Vite, Parcel, Next.js, or Remix でプロジェクトを作成するのをTailwindCSS公式では推奨している。(具体的なやり方はTailwindCSSドキュメントを参照、例:https://tailwindcss.com/docs/guides/vite)
エラー出る可能性あるので、「build時のエラー対応」の節に参照してください。
しかし、create-react-app
で作成したプロジェクトでもTailwindCSSを使用することは可能である。
インストール手順は以下の通り。
1
$ npx create-react-app my-project
$ cd my-project
2
npm install -D tailwindcss
npx tailwindcss init
3
tailwind.config.jsを設定する
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
4
index.cssを作成する
./src/index.css
に以下のように記載する。
@tailwind base;
@tailwind components;
@tailwind utilities;
これでTailwindCSSの設定は完了した。
4. ReactとDjangoとの連携
Django側でindex.html作成
Django側のアプリのディレクトリにtemplatesフォルダを作成し、その中にindex.htmlを作成する。
<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="utf-8">
<title>Reactアプリ</title>
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="{% static 'js/bundle.js' %}" ></script>
</body>
</html>
ここで、Bodyの内容はstatic/js/bundle.jsから読み込むようにしている。
bundle.jsはReactのビルドファイルで、React側でbuildを行うと作成される(React側での設定が必要)。
React側で必要なモジュールをインストールする
JavaScriptの場合には、babel-loaderを使用するが、TypeScriptの場合には、ts-loaderを使用する。
JavaScript: $ npm install --save-dev babel-loader
TypeScript: $ npm install --save-dev ts-loader
React側でwebpack.config.jsを作成
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js', //buildするファイル
output: {
filename: 'bundle.js', //build後のファイル名
path: path.join(__dirname, '../django_react/react_app/static/js') //buildファイルが作成される場所
},
module: {
rules: [
//JavaScriptの場合のloader設定
{
test: /\.js[x]?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
],
plugins: ['@babel/plugin-syntax-jsx']
}
}
}
//Typescriptの場合のloader設定
{
test: /\.ts[x]?$/,
exclude: /node_modules/,
use: 'ts-loader',
},
//TailwindCSSファイルを読み込むための設定
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
ident: 'postcss',
plugins: [
require('tailwindcss'),
require('autoprefixer'),
],
},
},
},
],
},
],
},
resolve: {
extensions: ['.js', '.jsx', '.json']
}
};
.envファイルを作成
パッケージ間の依存関係のチェックをスキップするようにするのである。
.envファイルを作成して下記のように記載する。
SKIP_PREFLIGHT_CHECK=true
build
buildしてみる。
$ npx webpack
でnpm scriptによらず、直接webpackコマンドを実行する。(npm 5.2+ )
build時のエラー対応
エラー内容:TypeScript emitted no output for…
Module build failed (from ./node_modules/ts-loader/index.js):
Error: TypeScript emitted no output for...
対応法
tsconfig.json
ファイルをチェック
-
noEmit
がtrueの場合、 TypeScriptはファイルを生成しない。{ "compilerOptions": { // ... "noEmit": false, // ... } }
-
sourceMap
の生成を禁止する{ "compilerOptions": { // ... "sourceMap": false, // ... } }
TailwindCSSのエラー
ERROR in ./src/index.css 1:0
Module parse failed: Unexpected character '@' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> @tailwind base;
| @tailwind components;
| @tailwind utilities;
対応手順
-
必要とされるloadersとPostCSSをインストールする
- npm:
$ npm install style-loader css-loader postcss-loader tailwindcss postcss autoprefixer --save-dev
- yarn:
$ yarn add style-loader css-loader postcss-loader tailwindcss postcss autoprefixer --dev
- npm:
-
webpackを設定
webpack.config.jsに以下を追加する。module: { rules: [ //TailwindCSSファイルを読み込むための設定 { test: /\.css$/, use: [ 'style-loader', 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { ident: 'postcss', plugins: [ require('tailwindcss'), require('autoprefixer'), ], }, }, }, ], }, ], },
-
PostCSSファイルを設定する
- postcss.config.jsがない場合は、Reactプロジェクトのディレクトリで作成する。
- TailwindCSSとAutoprefixer設定を以下のように記入する
module.exports = { plugins: { tailwindcss: {}, autoprefixer: {}, }, }
5. ReactでAPIを叩く
Axiosをインストール
ReactでAPIを叩くためのライブラリをインストールする。
$ npm install axios
エラー対応
下記のエラーが出る可能性がある。
npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR!
npm ERR! While resolving: react-scripts@5.0.1
npm ERR! Found: typescript@5.2.2
対応法として、package.jsonのdependenciesに記載されているバージョンを変更する。
package.jsonに下記のように追加して記載する
"overrides": {
"typescript": "^5.2.2",
},
APIを叩く
Reactのコンポーネントの中でaxiosを使用してAPIを叩く。
import React, {useState, useEffect} from 'react';
import axios from 'axios';
const Content = () => {
interface User {
user_id: string;
}
const [userInfo, setUserInfo] = useState<User[]>([]);
useEffect(() => {
axios.get('http://localhost:8000/api/user/')
.then(res => {
setUserInfo(res.data);
});
}, []);
return (
<div>
<div>
{userInfo.map(user => <div key={user.user_id}>{user.user_id}</div>)}
</div>
</div>
);
}
export default Content;
ここで、axiosでAPIにアクセスし、DBのデータを取得し、そのデータを画面に表示している。