Edited at

Django+Reactアプリケーション開発の準備 ルーティング設定とReactのビルド自動化


はじめに

Djangoのプロジェクト内にReact appを作成するだけでは、それぞれ


  • Django => 8000 port

  • React => 3000 port

というポートで接続して確認することになります。


  • ReactのWelcomeページを8000番で表示

  • Bootstrapの適用

  • Reactのビルド自動化

までやりたいと思います。

(Djangoのサーバを起動したときに同時にビルドするようになります)


セットアップ

$ django-admin startproject project

$ cd project
$ create-react-app frontend
$ cd frontend
$ yarn run build

django project内にreact appを作成してビルドしました。

起動してみます。

$ ./manage.py runserver

このままの状態では、8000番ポートに出力されるのはdjangoプロジェクトのスタートページです。

まずこれをReactのWelcomeページにしたい。


ReactのWelcomeページを8000番で表示

設定ファイルを以下のように編集します。


project/settings.py


......

# DIRSを追記

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'frontend', 'build'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

......

STATIC_URL = '/static/'

# STATICFILES_DIRSを追記
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'frontend', 'build', 'static'),
]



project/urls.py

from django.contrib import admin

from django.urls import path, re_path
from django.views.generic import TemplateView

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

re_path('.*', TemplateView.as_view(template_name='index.html')),
]


これで、以下のように8000番ポートでReactのWelcome画面にルーティングされるようになりました。


Bootstrapを適用してみる

とりあえずgetbootstrap.comからproject/frontend/public/index.htmlにコピペ


project/frontend/public/index.html

<!doctype html>

<html lang="ja-jp">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">

<title>Hello, world!</title>
</head>
<body>
<!-- ここだけ追記 -->
<div id="root"></div>
<h1>Hello, world!</h1>

<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</body>
</html>


ビルドしてサーバ起動。

$ pwd

project/frontend

$ yarn run build

$ cd ../

$ ./manage.py runserver

ブラウザで確認。

オッケ〜:thumbsup:


build自動化

このままわざわざfrontendに行ってbuildするのは面倒なので、runserverと同時にビルドするように設定します。

./manage.py runserver reactとしたとき、ビルドするようにします。

つまり、argv(argument vector:コマンドライン引数)の3つ目がreactのときにです。


manage.py

#!/usr/bin/env python

import os
import sys

if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc

# 以下追記

try:
if sys.argv[2] == "react":
project_root = os.getcwd()
os.chdir(os.path.join(project_root, "frontend"))
os.system("yarn run build")
os.chdir(project_root)
sys.argv.pop(2)
execute_from_command_line(sys.argv)
except IndexError:
execute_from_command_line(sys.argv)
else:
execute_from_command_line(sys.argv)


(例外処理しないと何故かsys.argv[2]なんてないと怒られます

print(sys.argv[2])で普通に出力されるのになんででしょう?教えてください...:bow_tone1:

適当にproject/frontend/public/index.htmlを編集して./manage.py runserver reactを実行してみましょう。

これだけでReactがビルドされて出力結果が変わっているはずです。


参考

https://www.youtube.com/watch?v=kmpY6g5hYZI を参考にしています。

というか結構そのまま日本語にしてます。